From 76d99a3d85349a091b4fef7dee7b39156c358e76 Mon Sep 17 00:00:00 2001
From: Shivesh Ranjan
Date: Sun, 7 Jun 2020 19:23:39 -0700
Subject: [PATCH 01/70] copying over changes to new fork
Signed-off-by: Shivesh Ranjan
---
build.gradle | 66 +-
.../client/SchemaRegistryClient.java | 358 ++++++++
.../client/SchemaRegistryClientConfig.java | 31 +
.../client/SchemaRegistryClientFactory.java | 25 +
.../client/SchemaRegistryClientImpl.java | 461 ++++++++++
.../client/exceptions/RegistryExceptions.java | 187 ++++
.../client/TestSchemaRegistryClient.java | 612 +++++++++++++
.../common/ContinuationTokenIterator.java | 93 ++
.../pravega/schemaregistry/common/Either.java | 51 ++
.../schemaregistry/common/HashUtil.java | 21 +
.../common/ContinuationTokenIteratorTest.java | 68 ++
.../contract/data/Compatibility.java | 203 ++++
.../contract/data/EncodingId.java | 35 +
.../contract/data/EncodingInfo.java | 33 +
.../contract/data/GroupHistoryRecord.java | 47 +
.../contract/data/GroupProperties.java | 74 ++
.../contract/data/SchemaInfo.java | 62 ++
.../contract/data/SchemaValidationRule.java | 23 +
.../contract/data/SchemaValidationRules.java | 66 ++
.../contract/data/SchemaWithVersion.java | 31 +
.../contract/data/SerializationFormat.java | 45 +
.../contract/data/VersionInfo.java | 47 +
.../generated/rest/model/AddedTo.java | 101 ++
.../generated/rest/model/CanRead.java | 92 ++
.../generated/rest/model/CodecTypesList.java | 101 ++
.../generated/rest/model/Compatibility.java | 216 +++++
.../rest/model/CreateGroupRequest.java | 117 +++
.../generated/rest/model/EncodingId.java | 92 ++
.../generated/rest/model/EncodingInfo.java | 144 +++
.../rest/model/GetEncodingIdRequest.java | 117 +++
.../generated/rest/model/GroupHistory.java | 101 ++
.../rest/model/GroupHistoryRecord.java | 194 ++++
.../generated/rest/model/GroupProperties.java | 179 ++++
.../rest/model/ListGroupsResponse.java | 128 +++
.../generated/rest/model/SchemaInfo.java | 179 ++++
.../rest/model/SchemaValidationRule.java | 92 ++
.../rest/model/SchemaValidationRules.java | 103 +++
.../rest/model/SchemaVersionsList.java | 102 +++
.../rest/model/SchemaWithVersion.java | 119 +++
.../rest/model/SerializationFormat.java | 154 ++++
.../model/UpdateValidationRulesRequest.java | 116 +++
.../contract/generated/rest/model/Valid.java | 92 ++
.../generated/rest/model/ValidateRequest.java | 117 +++
.../generated/rest/model/VersionInfo.java | 142 +++
.../rest/server/api/ApiException.java | 10 +
.../rest/server/api/ApiOriginFilter.java | 22 +
.../rest/server/api/ApiResponseMessage.java | 69 ++
.../generated/rest/server/api/Bootstrap.java | 31 +
.../generated/rest/server/api/GroupsApi.java | 412 +++++++++
.../rest/server/api/GroupsApiService.java | 54 ++
.../rest/server/api/JacksonJsonProvider.java | 18 +
.../rest/server/api/NotFoundException.java | 10 +
.../generated/rest/server/api/SchemasApi.java | 74 ++
.../rest/server/api/SchemasApiService.java | 22 +
.../generated/rest/server/api/StringUtil.java | 42 +
.../factories/GroupsApiServiceFactory.java | 13 +
.../factories/SchemasApiServiceFactory.java | 13 +
.../server/api/impl/GroupsApiServiceImpl.java | 134 +++
.../api/impl/SchemasApiServiceImpl.java | 26 +
.../contract/transform/ModelHelper.java | 243 +++++
.../schemaregistry/contract/v1/ApiV1.java | 554 +++++++++++
contract/src/main/swagger/README.md | 44 +
contract/src/main/swagger/SchemaRegistry.yaml | 867 ++++++++++++++++++
contract/src/main/swagger/server.config.json | 8 +
.../contract/transform/ModelHelperTest.java | 138 +++
65 files changed, 8240 insertions(+), 1 deletion(-)
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
create mode 100644 client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/Either.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
create mode 100644 common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
create mode 100644 contract/src/main/swagger/README.md
create mode 100644 contract/src/main/swagger/SchemaRegistry.yaml
create mode 100644 contract/src/main/swagger/server.config.json
create mode 100644 contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
diff --git a/build.gradle b/build.gradle
index a1f1bb5d6..52125793d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -34,7 +34,6 @@ buildscript {
}
}
dependencies {
- classpath group: 'com.google.protobuf', name:'protobuf-gradle-plugin', version: protobufGradlePlugin
classpath "gradle.plugin.org.nosphere.apache:creadur-rat-gradle:0.3.0"
classpath group: 'org.hidetake', name: 'gradle-ssh-plugin', version: gradleSshPluginVersion
classpath group: 'gradle.plugin.com.github.spotbugs', name: 'spotbugs-gradle-plugin', version: spotbugsPluginVersion
@@ -122,6 +121,71 @@ allprojects {
}
}
+project('common') {
+ dependencies {
+ compile group: 'commons-io', name: 'commons-io', version: commonsioVersion
+ compile group: 'com.google.guava', name: 'guava', version: guavaVersion
+ compile group: 'io.pravega', name: 'pravega-common', version: pravegaVersion
+ //Do NOT add any additional dependencies here.
+ }
+
+ javadoc {
+ title = "Common Libraries"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ options.addBooleanOption("Xdoclint:none", true)
+ }
+}
+
+project('client') {
+ dependencies {
+ compile project(':common')
+ compile project(':contract')
+ compile group: 'org.glassfish.jersey.ext', name: 'jersey-proxy-client', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: jerseyVersion
+ testCompile group: 'org.slf4j', name: 'log4j-over-slf4j', version: slf4jApiVersion
+ testCompile group: 'ch.qos.logback', name: 'logback-classic', version: qosLogbackVersion
+ testCompile group: 'io.pravega', name: 'pravega-test-testcommon', version: pravegaVersion
+ }
+
+ javadoc {
+ title = "Registry Client"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ exclude "**/impl/**";
+ options.addBooleanOption("Xdoclint:all,-reference", true)
+ }
+}
+
+project('contract') {
+ dependencies {
+ compile project(':common')
+ testCompile group: 'org.slf4j', name: 'log4j-over-slf4j', version: slf4jApiVersion
+ testCompile group: 'ch.qos.logback', name: 'logback-classic', version: qosLogbackVersion
+ compile group: 'javax.servlet', name: 'javax.servlet-api', version: javaxServletApiVersion
+ compile(group: 'io.swagger', name : 'swagger-jersey2-jaxrs', version :swaggerJersey2JaxrsVersion) {
+ exclude group: 'com.google.guava', module: 'guava'
+ }
+ compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: jerseyVersion
+ compile group: 'javax.xml.bind', name: 'jaxb-api', version: jaxbVersion
+ compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: jaxbVersion
+
+ }
+
+ javadoc {
+ title = "Registry Contract"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ exclude "**/impl/**";
+ options.addBooleanOption("Xdoclint:all,-reference", true)
+ }
+}
+
def getProjectVersion() {
String ver = schemaregistryVersion
if (grgit && ver.contains("-SNAPSHOT")) {
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
new file mode 100644
index 000000000..5ed87a3aa
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
@@ -0,0 +1,358 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+
+import javax.annotation.Nullable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+
+/**
+ * Defines a registry client for interacting with schema registry service.
+ * The implementation of this interface should provide atomicity and read-after-write-consistency guarantees for all the methods.
+ */
+public interface SchemaRegistryClient {
+ /**
+ * Adds a new group. A group refers to the name under which the schemas are registered. A group is identified by a
+ * unique name and has an associated set of group metadata {@link GroupProperties} and a list of codec types and a
+ * versioned history of schemas that were registered under the group.
+ * Add group is idempotent. If the group by the same name already exists the api will return false.
+ *
+ * @param groupId Id for the group that uniquely identifies the group.
+ * @param groupProperties groupProperties Group properties for the group. These include serialization format, validation rules,
+ * and flag to declare whether multiple schemas representing distinct object types can be
+ * registered with the group. Type identify objects of same type. Schema compatibility checks
+ * are always performed for schemas that share same {@link SchemaInfo#type}.
+ * Additionally, a user defined map of properties can be supplied.
+ * @return True indicates if the group was added successfully, false if it exists.
+ * @throws BadArgumentException if the group properties is rejected by service.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean addGroup(String groupId, GroupProperties groupProperties) throws BadArgumentException, UnauthorizedException;
+
+ /**
+ * Removes a group identified by the groupId. This will remove all the codec types and schemas registered under the group.
+ * Remove group is idempotent.
+ *
+ * @param groupId Id for the group that uniquely identifies the group.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void removeGroup(String groupId) throws UnauthorizedException;
+
+ /**
+ * List all groups that the user is authorized on. This returns an iterator where each element is a pair of group
+ * name and group properties.
+ * This iterator can be used to iterate over each element until all elements are exhausted.
+ * The implementation should guarantee that all groups added before and until the iterator returns
+ * {@link Iterator#hasNext()} = true can be iterated over.
+ *
+ * @return map of names of groups with corresponding group properties for all groups.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ Iterator> listGroups() throws UnauthorizedException;
+
+ /**
+ * Get group properties for the group identified by the group id.
+ *
+ * {@link GroupProperties#serializationFormat} which identifies the serialization format is used to describe the schema.
+ * {@link GroupProperties#schemaValidationRules} sets the schema validation policy that needs to be enforced for evolving schemas.
+ * {@link GroupProperties#allowMultipleTypes} that specifies if multiple schemas are allowed to be registered in the group.
+ * Schemas are validated against existing schema versions that have the same {@link SchemaInfo#type}.
+ * {@link GroupProperties#properties} describes generic properties for a group.
+ *
+ * @param groupId Id for the group.
+ * @return Group properties which includes property like Serialization format and compatibility policy.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ GroupProperties getGroupProperties(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Update group's schema validation policy. If previous rules are not supplied, then the update to the rules will be
+ * performed unconditionally. However, if previous rules are supplied, then the update will be performed if and only if
+ * existing {@link GroupProperties#schemaValidationRules} match previous rules.
+ *
+ * @param groupId Id for the group.
+ * @param validationRules New Schema validation rules for the group.
+ * @param previousRules Previous schema validation rules.
+ * @return true if the update was accepted by the service, false if it was rejected because of precondition failure.
+ * Precondition failure can occur if previous rules were specified and they do not match the rules set on the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean updateSchemaValidationRules(String groupId, SchemaValidationRules validationRules, @Nullable SchemaValidationRules previousRules)
+ throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets list of latest schemas for each object types registered under the group. Objects are identified by {@link SchemaInfo#type}.
+ * Schemas are retrieved atomically. So all schemas added before this call will be returned by this call.
+ *
+ * @param groupId Id for the group.
+ * @return List of different objects within the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getSchemas(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Registers schema to the group. Schemas are validated against existing schemas in the group that share the same
+ * {@link SchemaInfo#type}.
+ * If group is configured with {@link GroupProperties#allowMultipleTypes} then multiple schemas with distinct
+ * type {@link SchemaInfo#type} could be registered.
+ * All schemas with same type are assigned monotonically increasing version numbers.
+ * Add schema api is idempotent. If a schema is already registered, its version info is returned by the service.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to add.
+ * @return versionInfo which uniquely identifies where the schema is added in the group. If schema is already registered,
+ * then the existing version info is returned.
+ * @throws SchemaValidationFailedException if the schema is deemed invalid by applying schema validation rules which may
+ * include comparing schema with existing schemas for compatibility in the desired direction.
+ * @throws SerializationMismatchException if serialization format does not match the group's configured serialization format.
+ * @throws MalformedSchemaException for known serialization formats, if the service is unable to parse the schema binary or
+ * for avro and protobuf if the {@link SchemaInfo#type} does not match the name of record/message in the binary.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ VersionInfo addSchema(String groupId, SchemaInfo schemaInfo) throws SchemaValidationFailedException, SerializationMismatchException,
+ MalformedSchemaException, ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Api to delete schema corresponding to the version. Users should be very careful while using this API in production,
+ * esp if the schema has already been used to write the data.
+ * Delete schema api is idempotent.
+ * This does a soft delete of the schema. So getSchemaVersion with the version info will still return the schema.
+ * However, the schema will not participate in any compatibility checks once deleted.
+ * It will not be included in listing schema versions for the group using apis like {@link SchemaRegistryClient#getSchemaVersions}
+ * or {@link SchemaRegistryClient#getGroupHistory} or {@link SchemaRegistryClient#getSchemas} or
+ * {@link SchemaRegistryClient#getLatestSchemaVersion}
+ * If add schema is called again using this deleted schema will result in a new version being assigned to it upon registration.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo Version which uniquely identifies schema within a group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void deleteSchemaVersion(String groupId, VersionInfo versionInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Api to delete schema corresponding to the schemaType and version.
+ * Users should be very careful while using this API in production, esp if the schema has already been used to write the data.
+ * Delete schema api is idempotent.
+ * This does a soft delete of the schema. So getSchemaVersion with the version info will still return the schema.
+ * However, the schema will not participate in any compatibility checks once deleted.
+ * It will not be included in listing schema versions for the group using apis like {@link SchemaRegistryClient#getSchemaVersions}
+ * or {@link SchemaRegistryClient#getGroupHistory} or {@link SchemaRegistryClient#getSchemas} or
+ * {@link SchemaRegistryClient#getLatestSchemaVersion}
+ * If add schema is called again using this deleted schema will result in a new version being assigned to upon registration.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType schemaType that identifies the type of object the schema represents. This should be same as the
+ * value specified in {@link SchemaInfo#type}.
+ * @param version Version number which uniquely identifies schema for the schemaType within a group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void deleteSchemaVersion(String groupId, String schemaType, int version) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets schema corresponding to the version.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo Version which uniquely identifies schema within a group.
+ * @return Schema info corresponding to the version info.
+ * @throws ResourceNotFoundException if group or version is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaInfo getSchemaForVersion(String groupId, VersionInfo versionInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets schema corresponding to the version.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType schemaType as specified in the {@link SchemaInfo#type} while registering the schema.
+ * @param version Version which uniquely identifies schema of schemaType within a group.
+ * @return Schema info corresponding to the version info.
+ * @throws ResourceNotFoundException if group or version is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaInfo getSchemaForVersion(String groupId, String schemaType, int version) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets encoding info against the requested encoding Id. The purpose of encoding info is to uniquely identify the encoding
+ * used on the data at rest. The encoding covers two parts -
+ * 1. Schema that defines the structure of the data and is used for serialization. A specific schema version registered with
+ * registry service is uniquely identified by the corresponding VersionInfo object.
+ * 2. CodecType that is used to encode the serialized data. This would typically be some compression. The codecType
+ * and schema should both be registered with the service and service will generate a unique identifier for each such
+ * pair.
+ * Encoding Info uniquely identifies a combination of a versionInfo and codecType.
+ * EncodingInfo also includes the {@link SchemaInfo} identified by the {@link VersionInfo}.
+ *
+ * @param groupId Id for the group.
+ * @param encodingId Encoding id that uniquely identifies a schema within a group.
+ * @return Encoding info corresponding to the encoding id.
+ * @throws ResourceNotFoundException if group or encoding id is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ EncodingInfo getEncodingInfo(String groupId, EncodingId encodingId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets an encoding id that uniquely identifies a combination of Schema version and codec type.
+ * This encoding id is a 4 byte integer and it can be used to tag the data which is serialized and encoded using the
+ * schema version and codecType identified by this encoding id.
+ * This api is idempotent. And if an encoding id is generated for a version and codec pair, subsequent requests to this
+ * api will return the generated encoding id.
+ * If the schema identified by the version is deleted using {@link SchemaRegistryClient#deleteSchemaVersion} api,
+ * then if the encoding id was already generated for the pair of schema version and codec, then it will be returned.
+ * However, if no encoding id for the versioninfo and codec pair was generated and the schema version was deleted,
+ * then any call to getEncodingId using the deleted versionInfo will throw ResourceNotFoundException.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo version of schema
+ * @param codecType codec type
+ * @return Encoding id for the pair of version and codec type.
+ * @throws CodecTypeNotRegisteredException if codectype is not registered with the group. Use {@link SchemaRegistryClient#addCodecType}
+ * @throws ResourceNotFoundException if group or version info is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ EncodingId getEncodingId(String groupId, VersionInfo versionInfo, String codecType)
+ throws CodecTypeNotRegisteredException, ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets latest schema and version for the group (or type, if specified).
+ * To get latest schema version for a specific type identified by {@link SchemaInfo#type}, provide the type.
+ * Otherwise if the group is configured to allow multiple schemas {@link GroupProperties#allowMultipleTypes}, then
+ * and type is not specified, then last schema added to the group across all types will be returned.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType Type of object identified by {@link SchemaInfo#type}.
+ *
+ * @return Schema with version for the last schema that was added to the group (or type).
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaWithVersion getLatestSchemaVersion(String groupId, @Nullable String schemaType)
+ throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets version corresponding to the schema.
+ * For each schema type {@link SchemaInfo#type} and {@link SchemaInfo#serializationFormat} a versionInfo object uniquely
+ * identifies each distinct {@link SchemaInfo#schemaData}.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo SchemaInfo that describes format and structure.
+ * @return VersionInfo corresponding to schema.
+ * @throws ResourceNotFoundException if group is not found or if schema is not registered.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ VersionInfo getVersionForSchema(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets all schemas with corresponding versions for the group (or type, if specified).
+ * For groups configured with {@link GroupProperties#allowMultipleTypes}, the type {@link SchemaInfo#type} should be
+ * supplied to view schemas specific to a type. if type is null, all schemas in the group are returned.
+ * The order in the list matches the order in which schemas were evolved within the group.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType type of object identified by {@link SchemaInfo#type}.
+ * @return Ordered list of schemas with versions and validation rules for all schemas in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getSchemaVersions(String groupId, @Nullable String schemaType) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Checks whether given schema is valid by applying validation rules against previous schemas in the group
+ * subject to current {@link GroupProperties#schemaValidationRules} policy.
+ * This api performs exactly the same validations as {@link SchemaRegistryClient#addSchema(String, SchemaInfo)}
+ * but without registering the schema. This is primarily intended to be used during schema development phase to validate that
+ * the changes to schema are in compliance with validation rules for the group.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to check for validity.
+ * @return A schema is valid if it passes all the {@link GroupProperties#schemaValidationRules}. The rule supported
+ * presently, is Compatibility. If desired compatibility is satisfied by the schema then this api returns true, false otherwise.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean validateSchema(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Checks whether given schema can be used to read by validating it for reads against one or more existing schemas in the group
+ * subject to current {@link GroupProperties#schemaValidationRules} policy.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to check to be used for reads.
+ * @return True if it can be used to read, false otherwise.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean canReadUsing(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * List of codec types used for encoding in the group.
+ *
+ * @param groupId Id for the group.
+ * @return List of codec types used for encoding in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getCodecTypes(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Add new codec type to be used in encoding in the group.
+ *
+ * @param groupId Id for the group.
+ * @param codecType codec type.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void addCodecType(String groupId, String codecType) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets complete schema evolution history of the group with schemas, versions, rules and time for the group.
+ * The order in the list matches the order in which schemas were evolved within the group.
+ * This call is atomic and will get a consistent view at the time when the request is processed on the service.
+ * So all schemas that were added before this call are returned and all schemas that were deleted before this call
+ * are excluded.
+ *
+ * @param groupId Id for the group.
+ * @return Ordered list of schemas with versions and validation rules for all schemas in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getGroupHistory(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Finds all groups and corresponding version info for the groups where the supplied schema has been registered.
+ * It is important to note that the same schema type could be part of multiple group, however in each group it
+ * may have gone through a separate evolution. This api simply identifies all groups where the specific schema
+ * (type, format and binary) is used.
+ * The user defined {@link SchemaInfo#properties} is not used for comparison.
+ *
+ * @param schemaInfo Schema info to find references for.
+ * @return Map of group Id to versionInfo identifier for the schema in that group.
+ * @throws ResourceNotFoundException if schema is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ Map getSchemaReferences(SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
new file mode 100644
index 000000000..66bb39921
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.net.URI;
+
+/**
+ * Registry client configuration used to create registry client.
+ */
+@Data
+@Builder
+public class SchemaRegistryClientConfig {
+ /**
+ * URI for connecting with registry client.
+ */
+ private final URI schemaRegistryUri;
+
+ private SchemaRegistryClientConfig(URI schemaRegistryUri) {
+ this.schemaRegistryUri = schemaRegistryUri;
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
new file mode 100644
index 000000000..caba3d815
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+/**
+ * Factory class for creating Schema Registry client.
+ */
+public class SchemaRegistryClientFactory {
+ /**
+ * Factory method to create Schema Registry Client.
+ *
+ * @param config Configuration for creating registry client.
+ * @return SchemaRegistry client implementation
+ */
+ public static SchemaRegistryClient createRegistryClient(SchemaRegistryClientConfig config) {
+ return new SchemaRegistryClientImpl(config.getSchemaRegistryUri());
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
new file mode 100644
index 000000000..5e46b69c1
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
@@ -0,0 +1,461 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.pravega.common.Exceptions;
+import io.pravega.common.util.Retry;
+import io.pravega.schemaregistry.common.ContinuationTokenIterator;
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.transform.ModelHelper;
+import io.pravega.schemaregistry.contract.v1.ApiV1;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.proxy.WebResourceFactory;
+
+import javax.annotation.Nullable;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+
+public class SchemaRegistryClientImpl implements SchemaRegistryClient {
+ private static final Retry.RetryAndThrowConditionally RETRY = Retry
+ .withExpBackoff(100, 2, 10, 1000)
+ .retryWhen(x -> Exceptions.unwrap(x) instanceof ConnectionException);
+ private static final int GROUP_LIMIT = 100;
+ private static final int SCHEMA_LIMIT = 10;
+
+ private final ApiV1.GroupsApi groupProxy;
+ private final ApiV1.SchemasApi schemaProxy;
+
+ SchemaRegistryClientImpl(URI uri) {
+ Client client = ClientBuilder.newClient(new ClientConfig());
+ this.groupProxy = WebResourceFactory.newResource(ApiV1.GroupsApi.class, client.target(uri));
+ this.schemaProxy = WebResourceFactory.newResource(ApiV1.SchemasApi.class, client.target(uri));
+ }
+
+ @VisibleForTesting
+ SchemaRegistryClientImpl(ApiV1.GroupsApi groupProxy) {
+ this(groupProxy, null);
+ }
+
+ @VisibleForTesting
+ SchemaRegistryClientImpl(ApiV1.GroupsApi groupProxy, ApiV1.SchemasApi schemaProxy) {
+ this.groupProxy = groupProxy;
+ this.schemaProxy = schemaProxy;
+ }
+
+ @Override
+ public boolean addGroup(String groupId, GroupProperties groupProperties) {
+ return withRetry(() -> {
+ CreateGroupRequest request = new CreateGroupRequest().groupName(groupId).groupProperties(ModelHelper.encode(groupProperties));
+ Response response = groupProxy.createGroup(request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return true;
+ case CONFLICT:
+ return false;
+ case BAD_REQUEST:
+ throw new BadArgumentException("Group properties invalid. Verify that schema validation rules include compatibility.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to add the group.");
+ }
+ });
+ }
+
+ @Override
+ public void removeGroup(String groupId) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteGroup(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case NO_CONTENT:
+ return;
+ default:
+ throw new InternalServerError("Internal Service error. Failed to remove the group.");
+ }
+ });
+ }
+
+ @Override
+ public Iterator> listGroups() {
+ final Function>>> function =
+ continuationToken -> {
+ ListGroupsResponse entity = getListGroupsResponse(continuationToken);
+ List> map = new LinkedList<>();
+ for (Map.Entry entry : entity.getGroups().entrySet()) {
+ ModelHelper.decode(entry.getValue().getSerializationFormat());
+ map.add(new AbstractMap.SimpleEntry<>(entry.getKey(), ModelHelper.decode(entry.getValue())));
+ }
+ return new AbstractMap.SimpleEntry<>(entity.getContinuationToken(), map);
+ };
+
+ return new ContinuationTokenIterator<>(function, null);
+ }
+
+ private ListGroupsResponse getListGroupsResponse(String continuationToken) {
+ return withRetry(() -> {
+ Response response = groupProxy.listGroups(continuationToken, GROUP_LIMIT);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(ListGroupsResponse.class);
+ default:
+ throw new InternalServerError("Internal Service error. Failed to list groups.");
+ }
+ });
+ }
+
+ @Override
+ public GroupProperties getGroupProperties(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getGroupProperties(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to list groups.");
+ }
+ });
+ }
+
+ @Override
+ public boolean updateSchemaValidationRules(String groupId, SchemaValidationRules validationRules, @Nullable SchemaValidationRules previousRules) {
+ return withRetry(() -> {
+ UpdateValidationRulesRequest request = new UpdateValidationRulesRequest()
+ .validationRules(ModelHelper.encode(validationRules));
+ if (previousRules != null) {
+ request.setPreviousRules(ModelHelper.encode(previousRules));
+ }
+
+ Response response = groupProxy.updateSchemaValidationRules(groupId, request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CONFLICT:
+ return false;
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ case OK:
+ return true;
+ default:
+ throw new InternalServerError("Internal Service error. Failed to update schema validation rules.");
+ }
+ });
+ }
+
+ @Override
+ public List getSchemas(String groupId) {
+ return latestSchemas(groupId, null);
+ }
+
+ private List latestSchemas(String groupId, String type) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemas(groupId, type);
+ SchemaVersionsList objectsList = response.readEntity(SchemaVersionsList.class);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return objectsList.getSchemas().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get object types.");
+ }
+ });
+ }
+
+ @Override
+ public VersionInfo addSchema(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ Response response = groupProxy.addSchema(groupId, ModelHelper.encode(schemaInfo));
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ case CONFLICT:
+ throw new SchemaValidationFailedException("Schema is incompatible.");
+ case EXPECTATION_FAILED:
+ throw new SerializationMismatchException("Serialization format disallowed.");
+ case BAD_REQUEST:
+ throw new MalformedSchemaException("Schema is malformed. Verify the schema data and type");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to addSchema.");
+ }
+ });
+ }
+
+ @Override
+ public void deleteSchemaVersion(String groupId, VersionInfo versionInfo) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteSchemaFromVersionOrdinal(groupId, versionInfo.getOrdinal());
+ if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
+ throw new ResourceNotFoundException("Group not found.");
+ } else if (response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) {
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public void deleteSchemaVersion(String groupId, String schemaType, int version) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteSchemaVersion(groupId, schemaType, version);
+ if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
+ throw new ResourceNotFoundException("Group not found.");
+ } else if (response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) {
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaInfo getSchemaForVersion(String groupId, VersionInfo versionInfo) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaFromVersionOrdinal(groupId, versionInfo.getOrdinal());
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaInfo getSchemaForVersion(String groupId, String schemaType, int version) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaFromVersion(groupId, schemaType, version);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public EncodingInfo getEncodingInfo(String groupId, EncodingId encodingId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getEncodingInfo(groupId, encodingId.getId());
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Encoding not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get encoding info.");
+ }
+ });
+ }
+
+ @Override
+ public EncodingId getEncodingId(String groupId, VersionInfo versionInfo, String codecType) {
+ return withRetry(() -> {
+ GetEncodingIdRequest getEncodingIdRequest = new GetEncodingIdRequest();
+ getEncodingIdRequest.codecType(codecType)
+ .versionInfo(ModelHelper.encode(versionInfo));
+ Response response = groupProxy.getEncodingId(groupId, getEncodingIdRequest);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.EncodingId.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getEncodingId failed. Either Group or Version does not exist.");
+ case PRECONDITION_FAILED:
+ throw new CodecTypeNotRegisteredException(String.format("Codec type %s not registered.", codecType));
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get encoding info.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaWithVersion getLatestSchemaVersion(String groupId, @Nullable String schemaType) {
+ List list = latestSchemas(groupId, schemaType);
+ if (schemaType == null) {
+ return list.stream().max(Comparator.comparingInt(x -> x.getVersionInfo().getOrdinal())).orElse(null);
+ } else {
+ return list.get(0);
+ }
+ }
+
+ @Override
+ public List getSchemaVersions(String groupId, @Nullable String schemaType) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaVersions(groupId, schemaType);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ SchemaVersionsList schemaList = response.readEntity(SchemaVersionsList.class);
+ return schemaList.getSchemas().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getSchemaVersions failed. Group does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema versions for group.");
+ }
+ });
+ }
+
+ @Override
+ public List getGroupHistory(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getGroupHistory(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory history = response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory.class);
+ return history.getHistory().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getGroupHistory failed. Either Group or Version does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema evolution history for group.");
+ }
+ });
+ }
+
+ @Override
+ public Map getSchemaReferences(SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException {
+ return withRetry(() -> {
+ Response response = schemaProxy.getSchemaReferences(ModelHelper.encode(schemaInfo));
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ io.pravega.schemaregistry.contract.generated.rest.model.AddedTo addedTo = response
+ .readEntity(io.pravega.schemaregistry.contract.generated.rest.model.AddedTo.class);
+ return addedTo.getGroups().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, x -> ModelHelper.decode(x.getValue())));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getSchemaReferences failed. Either Group or Version does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema evolution history for group.");
+ }
+ });
+ }
+
+ @Override
+ public VersionInfo getVersionForSchema(String groupId, SchemaInfo schema) {
+ return withRetry(() -> {
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo schemaInfo = ModelHelper.encode(schema);
+
+ Response response = groupProxy.getSchemaVersion(groupId, schemaInfo);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema version.");
+ }
+ });
+ }
+
+ @Override
+ public boolean validateSchema(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ ValidateRequest validateRequest = new ValidateRequest()
+ .schemaInfo(ModelHelper.encode(schemaInfo));
+ Response response = groupProxy.validate(groupId, validateRequest);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(Valid.class).isValid();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error.");
+ }
+ });
+ }
+
+ @Override
+ public boolean canReadUsing(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo request = ModelHelper.encode(schemaInfo);
+ Response response = groupProxy.canRead(groupId, request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(CanRead.class).isCompatible();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error.");
+ }
+ });
+ }
+
+ @Override
+ public List getCodecTypes(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getCodecTypesList(groupId);
+ CodecTypesList list = response.readEntity(CodecTypesList.class);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return list.getCodecTypes();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Failed to get codecTypes. Internal server error.");
+ }
+ });
+ }
+
+ @Override
+ public void addCodecType(String groupId, String codecType) {
+ withRetry(() -> {
+ Response response = groupProxy.addCodecType(groupId, codecType);
+
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return;
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Failed to add codec type. Internal server error.");
+ }
+ });
+ }
+
+ private T withRetry(Supplier supplier) {
+ return RETRY.run(supplier::get);
+ }
+
+ private void withRetry(Runnable runnable) {
+ RETRY.run(() -> {
+ runnable.run();
+ return null;
+ });
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java b/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
new file mode 100644
index 000000000..7bbb28966
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client.exceptions;
+
+import com.google.common.base.Preconditions;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+public class RegistryExceptions extends RuntimeException {
+ /**
+ * Enum to describe the type of exception.
+ */
+ public enum Type {
+ UNAUTHORIZED,
+ BAD_ARGUMENT,
+ PRECONDITION_FAILED,
+ CODEC_NOT_FOUND,
+ MALFORMED_SCHEMA,
+ INCOMPATIBLE_SCHEMA,
+ RESOURCE_NOT_FOUND,
+ SERIALIZATION_FORMAT_MISMATCH,
+ CONNECTION_ERROR,
+ INTERNAL_SERVER_ERROR
+ }
+
+ /**
+ * Trait to identify whether an exception is retryable or not.
+ */
+ public interface RetryableException {
+ }
+
+ /**
+ * Construct a StoreException.
+ *
+ * @param errorMessage The detailed error message.
+ */
+ public RegistryExceptions(final String errorMessage) {
+ super(errorMessage);
+ }
+
+ /**
+ * Factory method to construct Store exceptions.
+ *
+ * @param type Type of Exception.
+ * @param errorMessage The detailed error message.
+ * @return Instance of type of StoreException.
+ */
+ public static RegistryExceptions create(final Type type, final String errorMessage) {
+ Preconditions.checkArgument(errorMessage != null && !errorMessage.isEmpty(),
+ "Either cause or errorMessage should be non-empty");
+ RegistryExceptions exception;
+ switch (type) {
+ case UNAUTHORIZED:
+ exception = new UnauthorizedException(errorMessage);
+ break;
+ case BAD_ARGUMENT:
+ exception = new BadArgumentException(errorMessage);
+ break;
+ case PRECONDITION_FAILED:
+ exception = new PreconditionFailedException(errorMessage);
+ break;
+ case CODEC_NOT_FOUND:
+ exception = new CodecTypeNotRegisteredException(errorMessage);
+ break;
+ case INCOMPATIBLE_SCHEMA:
+ exception = new SchemaValidationFailedException(errorMessage);
+ break;
+ case RESOURCE_NOT_FOUND:
+ exception = new ResourceNotFoundException(errorMessage);
+ break;
+ case SERIALIZATION_FORMAT_MISMATCH:
+ exception = new SerializationMismatchException(errorMessage);
+ break;
+ case CONNECTION_ERROR:
+ exception = new ConnectionException(errorMessage);
+ break;
+ case INTERNAL_SERVER_ERROR:
+ exception = new InternalServerError(errorMessage);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid exception type");
+ }
+ return exception;
+ }
+
+ /**
+ * User is unauthorized to perform requested action.
+ */
+ public static class UnauthorizedException extends RegistryExceptions {
+ public UnauthorizedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Service rejected the supplied arguments with bad argument exception.
+ */
+ public static class BadArgumentException extends RegistryExceptions {
+ public BadArgumentException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Service rejected the request because the expected precondition for the requested action was not satisfied.
+ */
+ public static class PreconditionFailedException extends RegistryExceptions {
+ public PreconditionFailedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The requested codecType is not added to the group.
+ */
+ public static class CodecTypeNotRegisteredException extends RegistryExceptions {
+ public CodecTypeNotRegisteredException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Schema is malformed. Verify the schema data and type.
+ */
+ public static class MalformedSchemaException extends RegistryExceptions {
+ public MalformedSchemaException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The schema validation failed as it was validated against the ValidationRules set for the group.
+ */
+ public static class SchemaValidationFailedException extends RegistryExceptions {
+ public SchemaValidationFailedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Requested resource not found.
+ */
+ public static class ResourceNotFoundException extends RegistryExceptions {
+ public ResourceNotFoundException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Serialization format is not allowed for the group. Check {@link SchemaInfo#serializationFormat} with
+ * {@link GroupProperties#serializationFormat}.
+ */
+ public static class SerializationMismatchException extends RegistryExceptions {
+ public SerializationMismatchException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Exception type due to failure in connecting to the service.
+ */
+ public static class ConnectionException extends RegistryExceptions implements RetryableException {
+ public ConnectionException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The request processing failed on the service.
+ */
+ public static class InternalServerError extends RegistryExceptions implements RetryableException {
+ public InternalServerError(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+}
diff --git a/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java b/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
new file mode 100644
index 000000000..f4427b183
--- /dev/null
+++ b/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
@@ -0,0 +1,612 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import io.pravega.schemaregistry.contract.data.Compatibility;
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.SerializationFormat;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.transform.ModelHelper;
+import io.pravega.schemaregistry.contract.v1.ApiV1;
+import io.pravega.test.common.AssertExtensions;
+import lombok.val;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+public class TestSchemaRegistryClient {
+ @Test
+ public void testGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+
+ // add group
+ // 1. success response code
+ io.pravega.schemaregistry.contract.data.GroupProperties groupProperties = new io.pravega.schemaregistry.contract.data.GroupProperties(
+ SerializationFormat.Avro, SchemaValidationRules.of(Compatibility.backward()), true);
+ doReturn(response).when(proxy).createGroup(any());
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ boolean addGroup = client.addGroup("grp1", groupProperties);
+ assertTrue(addGroup);
+
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ addGroup = client.addGroup("grp1", groupProperties);
+ assertFalse(addGroup);
+
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("Exception should have been thrown",
+ () -> client.addGroup("grp1", groupProperties),
+ e -> e instanceof InternalServerError);
+ reset(response);
+
+ // list groups
+ doReturn(response).when(proxy).listGroups(null, 100);
+ Response response2 = mock(Response.class);
+ doReturn(response2).when(proxy).listGroups("token", 100);
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ doReturn(Response.Status.OK.getStatusCode()).when(response2).getStatus();
+ GroupProperties mygroup = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ String groupName = "mygroup";
+ ListGroupsResponse groupList = new ListGroupsResponse().groups(Collections.singletonMap(groupName, mygroup)).continuationToken("token");
+ doReturn(groupList).when(response).readEntity(eq(ListGroupsResponse.class));
+ doReturn(new ListGroupsResponse().groups(Collections.emptyMap()).continuationToken("token")).when(response2).readEntity(eq(ListGroupsResponse.class));
+
+ val groups = Lists.newArrayList(client.listGroups());
+ assertEquals(1, groups.size());
+ assertTrue(groups.stream().anyMatch(x -> x.getKey().equals(groupName)));
+ Map.Entry group =
+ groups.stream().filter(x -> x.getKey().equals(groupName)).findAny().orElseThrow(RuntimeException::new);
+ assertEquals(group.getValue().getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(group.getValue().getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()), Compatibility.backward());
+
+ reset(response);
+ }
+
+ @Test
+ public void testListGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ GroupProperties mygroup = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ String groupId = "mygroup";
+ ListGroupsResponse groupList = new ListGroupsResponse().groups(Collections.singletonMap(groupId, mygroup)).continuationToken("token");
+ ListGroupsResponse groupList2 = new ListGroupsResponse().groups(Collections.emptyMap()).continuationToken("token");
+ doReturn(response).when(proxy).listGroups(null, 100);
+ Response response2 = mock(Response.class);
+ doReturn(response2).when(proxy).listGroups("token", 100);
+ doReturn(Response.Status.OK.getStatusCode()).when(response2).getStatus();
+
+ doReturn(groupList).when(response).readEntity(eq(ListGroupsResponse.class));
+ doReturn(groupList2).when(response2).readEntity(eq(ListGroupsResponse.class));
+ val groups = Lists.newArrayList(client.listGroups());
+ assertEquals(1, groups.size());
+ assertTrue(groups.stream().anyMatch(x -> x.getKey().equals(groupId)));
+ Map.Entry group =
+ groups.stream().filter(x -> x.getKey().equals(groupId)).findAny().orElseThrow(RuntimeException::new);
+ assertEquals(group.getValue().getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(group.getValue().getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()), Compatibility.backward());
+
+ // Runtime Exception
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("Exception should have been thrown", () -> Lists.newArrayList(client.listGroups()), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testRemoveGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).deleteGroup(anyString());
+ doReturn(Response.Status.NO_CONTENT.getStatusCode()).when(response).getStatus();
+
+ client.removeGroup("mygroup");
+
+ // not OK response
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.removeGroup("mygroup"),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetGroupProperties() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getGroupProperties(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ GroupProperties mygroup
+ = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(
+ io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ doReturn(mygroup).when(response).readEntity(eq(GroupProperties.class));
+ io.pravega.schemaregistry.contract.data.GroupProperties groupProperties = client.getGroupProperties("mygroup");
+ assertEquals(groupProperties.getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(groupProperties.getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()),
+ Compatibility.backward());
+ // ResourceNotFoundException
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getGroupProperties(
+ "mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getGroupProperties(
+ "mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testUpdateSchemaValidationRules() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).updateSchemaValidationRules(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.backward());
+ client.updateSchemaValidationRules("mygroup", schemaValidationRules, null);
+ assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+ // Precondition Failed
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ assertFalse(client.updateSchemaValidationRules("mygroup", schemaValidationRules, null));
+ // NotFound exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.updateSchemaValidationRules("mygroup", schemaValidationRules, null),
+ e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.updateSchemaValidationRules("mygroup", schemaValidationRules, null),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testSchemasApi() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemas(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema1", 5, 5);
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion schemaVersion = new io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion()
+ .schemaInfo(ModelHelper.encode(schemaInfo)).version(ModelHelper.encode(versionInfo));
+ SchemaVersionsList schemaList = new SchemaVersionsList();
+ schemaList.addSchemasItem(schemaVersion);
+ doReturn(schemaList).when(response).readEntity(SchemaVersionsList.class);
+ List output = client.getSchemas("mygroup");
+ assertEquals(1, output.size());
+ assertEquals("schema1", output.get(0).getSchemaInfo().getType());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getSchemas("mygroup"),
+ e -> e instanceof ResourceNotFoundException);
+ // Runtime exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getSchemas("mygroup"),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testAddSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).addSchema(anyString(), any());
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo versionInfo =
+ new io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo().version(
+ 5).type("schema2").ordinal(5);
+ doReturn(versionInfo).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class);
+ VersionInfo versionInfo1 = client.addSchema("mygroup", schemaInfo);
+ assertEquals(5, versionInfo1.getVersion());
+ assertEquals("schema2", versionInfo1.getType());
+ assertEquals(5, versionInfo1.getOrdinal());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ // SchemaIncompatible exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof SchemaValidationFailedException);
+ // SerializationFormatInvalid Exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof SerializationMismatchException);
+ //Runtime Exception
+ doReturn(Response.Status.BAD_GATEWAY.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaFromVersionOrdinal(anyString(), anyInt());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat serializationFormat = ModelHelper.encode(SerializationFormat.custom("custom"));
+ byte[] schemaData = new byte[0];
+
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo schemaInfo =
+ new io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo()
+ .schemaData(schemaData).type("schema1").serializationFormat(serializationFormat).properties(Collections.emptyMap());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ doReturn(schemaInfo).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class);
+ SchemaInfo schemaInfo1 = client.getSchemaForVersion("mygroup", versionInfo);
+ assertEquals(schemaInfo.getType(), schemaInfo1.getType());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getSchemaForVersion("mygroup", versionInfo), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getSchemaForVersion("mygroup", versionInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetEncodingInfo() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getEncodingInfo(anyString(), anyInt());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ String codecType = "gzip";
+ EncodingInfo encodingInfo = new EncodingInfo(versionInfo, schemaInfo, codecType);
+ EncodingId encodingId = new EncodingId(5);
+ doReturn(ModelHelper.encode(encodingInfo)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo.class);
+ EncodingInfo encodingInfo1 = client.getEncodingInfo("mygroup", encodingId);
+ assertEquals(encodingInfo.getCodecType(), encodingInfo1.getCodecType());
+ assertEquals(encodingInfo.getSchemaInfo(), encodingInfo1.getSchemaInfo());
+ assertEquals(encodingInfo.getVersionInfo(), encodingInfo1.getVersionInfo());
+ // NotFound exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingInfo("mygroup", encodingId), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingInfo("mygroup", encodingId), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetEncodingId() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getEncodingId(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingId encodingId = ModelHelper.encode(new EncodingId(5));
+ doReturn(encodingId).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingId.class);
+ EncodingId encodingId1 = client.getEncodingId("mygroup", versionInfo, codecType);
+ assertEquals(encodingId.getEncodingId().intValue(), encodingId1.getId());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof ResourceNotFoundException);
+ // StringNotFound Exception
+ doReturn(Response.Status.PRECONDITION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof CodecTypeNotRegisteredException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetLatestSchemaForGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemas(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ SchemaWithVersion schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ SchemaVersionsList schemaWithVersions = new SchemaVersionsList().schemas(Collections.singletonList(ModelHelper.encode(schemaWithVersion)));
+ doReturn(schemaWithVersions).when(response).readEntity(
+ SchemaVersionsList.class);
+ SchemaWithVersion schemaWithVersion1 = client.getLatestSchemaVersion("mygroup", null);
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaWithVersion1.getSchemaInfo());
+ assertEquals(schemaWithVersion.getVersionInfo(), schemaWithVersion1.getVersionInfo());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", null), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", null), e -> e instanceof InternalServerError);
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ versionInfo = new VersionInfo("schema2", 5, 5);
+ serializationFormat = SerializationFormat.custom("custom");
+ schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ doReturn(ModelHelper.encode(schemaWithVersion)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion.class);
+ schemaWithVersion1 = client.getLatestSchemaVersion("mygroup", "myobject");
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaWithVersion1.getSchemaInfo());
+ assertEquals(schemaWithVersion.getVersionInfo(), schemaWithVersion1.getVersionInfo());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", "myobject"), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", "myobject"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGroupEvolutionHistory() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getGroupHistory(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.backward());
+ GroupHistoryRecord groupHistoryRecord = new io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord()
+ .schemaInfo(ModelHelper.encode(schemaInfo)).version(ModelHelper.encode(versionInfo))
+ .validationRules(ModelHelper.encode(schemaValidationRules)).timestamp(100L).schemaString("");
+ GroupHistory history = new GroupHistory();
+ history.addHistoryItem(groupHistoryRecord);
+ doReturn(history).when(response).readEntity(GroupHistory.class);
+ List groupHistoryList = client.getGroupHistory("mygroup");
+ assertEquals(1, groupHistoryList.size());
+ assertEquals(schemaValidationRules, groupHistoryList.get(0).getRules());
+ assertEquals(schemaInfo, groupHistoryList.get(0).getSchema());
+ assertEquals(versionInfo, groupHistoryList.get(0).getVersion());
+ assertEquals(100L, groupHistoryList.get(0).getTimestamp());
+ assertEquals("", groupHistoryList.get(0).getSchemaString());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getGroupHistory("mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getGroupHistory("mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchemaVersion() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaVersion(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ doReturn(ModelHelper.encode(versionInfo)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class);
+ VersionInfo versionInfo1 = client.getVersionForSchema("mygroup", schemaInfo);
+ assertEquals(versionInfo.getType(), versionInfo1.getType());
+ assertEquals(versionInfo.getVersion(), versionInfo1.getVersion());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getVersionForSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getVersionForSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchemaVersions() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaVersions(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SchemaWithVersion schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ SchemaVersionsList list = new SchemaVersionsList().schemas(Collections.singletonList(ModelHelper.encode(schemaWithVersion)));
+ doReturn(list).when(response).readEntity(SchemaVersionsList.class);
+ List result = Lists.newArrayList(client.getSchemaVersions("mygroup", null));
+ assertEquals(result.size(), 1);
+ assertEquals(versionInfo, result.get(0).getVersionInfo());
+ assertEquals(schemaInfo, result.get(0).getSchemaInfo());
+
+ result = Lists.newArrayList(client.getSchemaVersions("mygroup", schemaInfo.getType()));
+ assertEquals(result.size(), 1);
+ assertEquals(versionInfo, result.get(0).getVersionInfo());
+ assertEquals(schemaInfo, result.get(0).getSchemaInfo());
+
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> Lists.newArrayList(client.getSchemaVersions("mygroup", null)),
+ e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> Lists.newArrayList(client.getSchemaVersions("mygroup", null)), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testValidateSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).validate(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ Valid valid = new Valid().valid(Boolean.TRUE);
+ doReturn(valid).when(response).readEntity(Valid.class);
+ Boolean valid1 = client.validateSchema("mygroup", schemaInfo);
+ assertEquals(valid.isValid(), valid1);
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.validateSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.validateSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testCanRead() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).canRead(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ CanRead canRead = new CanRead().compatible(Boolean.TRUE);
+ doReturn(canRead).when(response).readEntity(CanRead.class);
+ Boolean canRead1 = client.canReadUsing("mygroup", schemaInfo);
+ assertEquals(canRead.isCompatible(), canRead1);
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.canReadUsing("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.canReadUsing("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetCodecTypes() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getCodecTypesList(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ String codecType1 = "snappy";
+ CodecTypesList codecTypesList = new CodecTypesList();
+ codecTypesList.addCodecTypesItem(codecType);
+ codecTypesList.addCodecTypesItem(codecType1);
+ doReturn(codecTypesList).when(response).readEntity(CodecTypesList.class);
+ List codecTypesList1 = client.getCodecTypes("mygroup");
+ assertEquals(2, codecTypesList1.size());
+ assertEquals("gzip", codecTypesList1.get(0));
+ assertEquals("snappy", codecTypesList1.get(1));
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getCodecTypes("mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getCodecTypes("mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testAddCodecType() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).addCodecType(anyString(), any());
+
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ client.addCodecType("mygroup", codecType);
+ assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addCodecType("mygroup", codecType), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addCodecType("mygroup", codecType), e -> e instanceof InternalServerError);
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java b/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
new file mode 100644
index 000000000..ff998e60d
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import lombok.Synchronized;
+
+import javax.annotation.concurrent.GuardedBy;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.Function;
+
+/**
+ * Continuation token iterator which fetches a batch of values using the loading function. Once those values have been
+ * iterated over, it uses the continuation token to read more values using the loading function until the function does
+ * not return a value.
+ * @param Type of value.
+ * @param Type of continuation token.
+ */
+public class ContinuationTokenIterator implements Iterator {
+ @GuardedBy("$lock")
+ private final Queue queue;
+ private final Function>> loadingFunction;
+ @GuardedBy("lock")
+ private Token token;
+ @GuardedBy("$lock")
+ private T next;
+ @GuardedBy("$lock")
+ private boolean canHaveNext;
+ @GuardedBy("$lock")
+ private final Set tokens;
+
+ public ContinuationTokenIterator(Function>> loadingFunction, Token tokenIdentity) {
+ this.loadingFunction = loadingFunction;
+ this.queue = new LinkedBlockingQueue();
+ this.token = tokenIdentity;
+ this.canHaveNext = true;
+ this.next = null;
+ this.tokens = new HashSet<>();
+ }
+
+ @Synchronized
+ private void load() {
+ next = next == null ? queue.poll() : next;
+ while (next == null && canHaveNext) {
+ Map.Entry> result = loadingFunction.apply(token);
+ boolean tokenUpdated = result.getKey() != null && !tokens.contains(result.getKey());
+ if (result.getKey() != null) {
+ tokens.add(result.getKey());
+ }
+ token = result.getKey();
+
+ queue.addAll(result.getValue());
+ next = queue.poll();
+ if (next == null) {
+ canHaveNext = tokenUpdated;
+ }
+ }
+ }
+
+ @Synchronized
+ @Override
+ public boolean hasNext() {
+ load();
+ return canHaveNext;
+ }
+
+ @Synchronized
+ @Override
+ public T next() {
+ load();
+ if (next != null) {
+ T retVal = next;
+ next = null;
+ return retVal;
+ } else {
+ assert !canHaveNext;
+ throw new NoSuchElementException();
+ }
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/Either.java b/common/src/main/java/io/pravega/schemaregistry/common/Either.java
new file mode 100644
index 000000000..212ad99fe
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/Either.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.base.Preconditions;
+import lombok.Data;
+
+/**
+ * A holder object consisting of either of two elements.
+ *
+ * The objects could be of any type. Exactly one of the values will exist while the other will be null.
+ * If a mutable object is stored in 'Either', then 'Either' itself effectively becomes mutable.
+ *
+ * @param the left element type.
+ * @param the right element type.
+ */
+@Data
+public class Either {
+ private final T left;
+ private final K right;
+
+ private Either(T left, K right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ public static Either left(T t) {
+ Preconditions.checkNotNull(t);
+ return new Either(t, null);
+ }
+
+ public static Either right(K k) {
+ Preconditions.checkNotNull(k);
+ return new Either(null, k);
+ }
+
+ public boolean isLeft() {
+ return left != null;
+ }
+
+ public boolean isRight() {
+ return right != null;
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java b/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
new file mode 100644
index 000000000..3875cbb44
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+
+public class HashUtil {
+ private static final HashFunction HASH = Hashing.murmur3_128();
+
+ public static long getFingerprint(byte[] bytes) {
+ return HASH.hashBytes(bytes).asLong();
+ }
+}
diff --git a/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java b/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
new file mode 100644
index 000000000..89989512a
--- /dev/null
+++ b/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.collect.Lists;
+import lombok.Data;
+import org.junit.Test;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.Function;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class ContinuationTokenIteratorTest {
+ @Test
+ public void test() {
+ // 1. call method 1st call returns - list of 5 items + new token
+ // verify that call method is not called until all 10 are read.
+ // 2. call returns empty list + new token
+ // 3. call returns empty list + new token
+ // 4. call returns list of 10 items + new token
+ // verify that we consume 10 items without calling the callmethod
+ // 5. call returns empty list + same token. --> this should exit
+ Queue responses = spy(new LinkedBlockingQueue<>());
+ responses.add(new ListWithToken(Lists.newArrayList(1, 2, 3, 4, 5), "1"));
+ responses.add(new ListWithToken(Collections.emptyList(), "2"));
+ responses.add(new ListWithToken(Collections.emptyList(), "3"));
+ responses.add(new ListWithToken(Lists.newArrayList(6, 7, 8, 9, 10), "4"));
+ responses.add(new ListWithToken(Collections.emptyList(), "4"));
+ Function>> func = token -> {
+ ListWithToken result = responses.poll();
+ return new AbstractMap.SimpleEntry<>(result.token, result.list);
+ };
+ ContinuationTokenIterator myIterator = new ContinuationTokenIterator<>(func, null);
+ for (int i = 0; i < 5; i++) {
+ assertTrue(myIterator.hasNext());
+ assertEquals(myIterator.next().intValue(), i + 1);
+ }
+ verify(responses, times(1)).poll();
+ for (int i = 5; i < 10; i++) {
+ assertTrue(myIterator.hasNext());
+ assertEquals(myIterator.next().intValue(), i + 1);
+ }
+ verify(responses, times(4)).poll();
+ assertFalse(myIterator.hasNext());
+ verify(responses, times(5)).poll();
+ }
+
+ @Data
+ static class ListWithToken {
+ private final List list;
+ private final String token;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
new file mode 100644
index 000000000..f8717337c
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Defines different Compatibility policy options for schema evolution for schemas within a group.
+ * The choice of compatibility policy tells the Schema Registry service whether a schema should be accepted to evolve
+ * into new schema by comparing it with one or more existing versions of the schema.
+ *
+ * {@link Type#AllowAny}: allow any changes to schema without any checks performed by the registry.
+ * {@link Type#DenyAll}: disables any changes to the schema for the group.
+ * {@link Type#Backward}: a new schema can be used to read data written by previous schema.
+ * {@link Type#BackwardTransitive}: a new schema can be used read data written by any of previous schemas.
+ * {@link Type#BackwardTill}: a new schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ * {@link Type#Forward}: previous schema can be used to read data written by new schema.
+ * {@link Type#ForwardTransitive}: all previous schemas can read data written by new schema.
+ * {@link Type#ForwardTill}: All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema.
+ * {@link Type#Full}: both backward and forward compatibility.
+ * {@link Type#FullTransitive}: both backward and forward compatibility with all previous schemas.
+ * {@link Type#BackwardAndForwardTill}: All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema. New schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ */
+@Data
+@Builder
+public class Compatibility implements SchemaValidationRule {
+ /**
+ * Enum that defines the Type of compatibility policy.
+ */
+ private final Type compatibility;
+ /**
+ * Version info to be specified if the compatibility policy choic.e is either {@link Type#backwardTill} or
+ * {@link Type#backwardTillAndForwardTill}.
+ */
+ private final VersionInfo backwardTill;
+ /**
+ * Version info to be specified if the compatibility policy choice is either {@link Type#forwardTill} or
+ * {@link Type#backwardTillAndForwardTill}.
+ */
+ private final VersionInfo forwardTill;
+
+ private Compatibility(Type compatibility) {
+ this(compatibility, null, null);
+ }
+
+ public Compatibility(Type compatibility, VersionInfo backwardTill, VersionInfo forwardTill) {
+ this.compatibility = compatibility;
+ this.backwardTill = backwardTill;
+ this.forwardTill = forwardTill;
+ }
+
+ @Override
+ public String getName() {
+ return Compatibility.class.getSimpleName();
+ }
+
+ public enum Type {
+ AllowAny,
+ DenyAll,
+ Backward,
+ BackwardTill,
+ BackwardTransitive,
+ Forward,
+ ForwardTill,
+ ForwardTransitive,
+ BackwardAndForwardTill,
+ Full,
+ FullTransitive;
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward. Backward policy implies new schema will be validated
+ * to be capable of reading data written using the previous schema.
+ *
+ * @return Compatibility with Type.Backward.
+ */
+ public static Compatibility backward() {
+ return new Compatibility(Type.Backward);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward till. BackwardTill policy implies new schema will be validated
+ * to be capable of reading data written using the all previous schemas till version supplied as input.
+ *
+ * @param backwardTill version till which schemas should be checked for compatibility.
+ * @return Compatibility with Type.BackwardTill version.
+ */
+ public static Compatibility backwardTill(VersionInfo backwardTill) {
+ return new Compatibility(Type.BackwardTill, backwardTill, null);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward transitive. Backward transitive policy implies
+ * new schema will be validated to be capable of reading data written using the all previous schemas versions.
+ *
+ * @return Compatibility with Type.BackwardTransitive.
+ */
+ public static Compatibility backwardTransitive() {
+ return new Compatibility(Type.BackwardTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward. Forward policy implies new schema will be validated
+ * such that data written using new schema can be read using the previous schema.
+ *
+ * @return Compatibility with Type.Forward
+ */
+ public static Compatibility forward() {
+ return new Compatibility(Type.Forward);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward till. Forward policy implies new schema will be validated
+ * such that data written using new schema can be read using the all previous schemas till supplied version.
+ *
+ * @param forwardTill version till which schemas should be checked for compatibility.
+ * @return Compatibility with Type.ForwardTill version.
+ */
+ public static Compatibility forwardTill(VersionInfo forwardTill) {
+ return new Compatibility(Type.ForwardTill, null, forwardTill);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward transitive.
+ * Forward transitive policy implies new schema will be validated such that data written using new schema
+ * can be read using all previous schemas.
+ *
+ * @return Compatibility with Type.ForwardTransitive.
+ */
+ public static Compatibility forwardTransitive() {
+ return new Compatibility(Type.ForwardTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type full. Full means backward and forward compatibility check with
+ * previous schema version. Which means new schema can be used to read data written with previous schema and vice versa.
+ *
+ * @return Compatibility with Type.Full.
+ */
+ public static Compatibility full() {
+ return new Compatibility(Type.Full);
+ }
+
+ /**
+ * Method to create a compatibility policy of type full transitive.
+ * Full transitive means backward and forward compatibility check with all previous schema version.
+ * This implies new schema can be used to read data written with any of the previous schemas and vice versa.
+ *
+ * @return Compatibility with Type.FullTransitive.
+ */
+ public static Compatibility fullTransitive() {
+ return new Compatibility(Type.FullTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward till and forward till. This is a combination of
+ * backward till and forward till policies.
+ * All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema. New schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ *
+ * @param backwardTill version till which backward compatibility is checked for.
+ * @param forwardTill version till which forward compatibility is checked for.
+ * @return Compatibility with Type.FullTransitive.
+ */
+ public static Compatibility backwardTillAndForwardTill(VersionInfo backwardTill, VersionInfo forwardTill) {
+ return new Compatibility(Type.BackwardAndForwardTill, backwardTill, forwardTill);
+ }
+
+ /**
+ * Disable compatibility check and all any schema to be registered. Effectively declares all schemas as compatible.
+ *
+ * @return Compatibility with Type.AllowAny
+ */
+ public static Compatibility allowAny() {
+ return new Compatibility(Type.AllowAny);
+ }
+
+ /**
+ * Compatibility policy that disallows any new schema changes. Effecfively rejects all schemas and declares them incompatible.
+ *
+ * @return Compatibility with Type.DenyAll
+ */
+ public static Compatibility denyAll() {
+ return new Compatibility(Type.DenyAll);
+ }
+
+ public static class CompatibilityBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
new file mode 100644
index 000000000..2d1d625ca
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * For each group unique set of Encoding Ids are generated for each unique combination of schema version and codec types
+ * registered in the group.
+ * The encoding id will typically be attached to the encoded data in a header to describe how to parse the following data.
+ * The registry service exposes APIs to resolve encoding id to {@link EncodingInfo} objects that include details about the
+ * encoding used.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class EncodingId {
+ /**
+ * A 4byte id that uniquely identifies a {@link VersionInfo} and codecType pair.
+ */
+ private final int id;
+
+ public static class EncodingIdBuilder implements ObjectBuilder {
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
new file mode 100644
index 000000000..f5e396ea2
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.Data;
+
+/**
+ * Encoding Info describes the details of encoding for each event payload. Each combination of schema version and codec type
+ * is uniquely identified by an {@link EncodingId}.
+ * The registry service exposes APIs to generate or resolve {@link EncodingId} to {@link EncodingInfo}.
+ */
+@Data
+public class EncodingInfo {
+ /**
+ * Version of the schema which is used in encoding the data.
+ */
+ private final VersionInfo versionInfo;
+ /**
+ * Actual schema which is used in encoding the data.
+ */
+ private final SchemaInfo schemaInfo;
+ /**
+ * Codec type which is used in encoding the data.
+ */
+ private final String codecType;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
new file mode 100644
index 000000000..4b9a3d257
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.Data;
+
+/**
+ * Describes changes to the group and the validation rules {@link GroupHistoryRecord#rules} that were
+ * applied while registering {@link GroupHistoryRecord#schema} and the unique {@link GroupHistoryRecord#version} identifier
+ * that was assigned to it.
+ * It also has {@link GroupHistoryRecord#timestamp} when the schema was added and includes an optional
+ * {@link GroupHistoryRecord#schemaString} which is populated only if serialization format is one of {@link SerializationFormat#Avro}
+ * {@link SerializationFormat#Json} or {@link SerializationFormat#Protobuf}. This string is just to help make the schema human readable.
+ */
+@Data
+public class GroupHistoryRecord {
+ /**
+ * Schema information object for the schema that was added to the group.
+ */
+ private final SchemaInfo schema;
+ /**
+ * Version information object that uniquely identifies the schema in the group.
+ */
+ private final VersionInfo version;
+ /**
+ * Validation rules that were applied at the time when the schema was registered.
+ */
+ private final SchemaValidationRules rules;
+ /**
+ * Service's Time when the schema was registered.
+ */
+ private final long timestamp;
+ /**
+ * A json format string representing the schema. This string will be populated only for serialization formats
+ * that the service can parse.
+ */
+ private final String schemaString;
+}
+
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
new file mode 100644
index 000000000..4002ceebb
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.collect.ImmutableMap;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Different configuration choices for a group.
+ *
+ * {@link GroupProperties#serializationFormat} identifies the serialization format used to describe the schema.
+ * {@link GroupProperties#schemaValidationRules} sets the schema validation policy that needs to be enforced for evolving schemas.
+ * {@link GroupProperties#allowMultipleTypes} that specifies if multiple schemas with distinct {@link SchemaInfo#type}
+ * are allowed to coexist within the group. A schema describes an object and each object type is distinctly identified by
+ * {@link SchemaInfo#type}. Registry service validates new schema with existing schema versions of the same name and versions
+ * it accordingly. Allowing multiple schemas, each versioned independently, allows applications to use schema registry groups
+ * for streaming scenarios like event sourcing, or message bus where different types of events could be written to the same
+ * stream. Similarly, a group with multiple schemas can be used to describe a database catalog with each schema representing
+ * a different table.
+ * The users can register new versions of each distinct type of schema, and the registry will check for compatibility
+ * for each type independently.
+ * {@link GroupProperties#properties} This is general purpose key value string to include any additional user defined information for the group.
+ */
+@Builder
+@Data
+public class GroupProperties {
+ /**
+ * Serialization format allowed for the group.
+ */
+ private final SerializationFormat serializationFormat;
+ /**
+ * Schema validation rules to be applied for the group.
+ */
+ private final SchemaValidationRules schemaValidationRules;
+ /**
+ * Flag to indicate whether multiple types of schemas can be added to the group or not. If set to false, all schemas
+ * added to the group should have the same {@link SchemaInfo#type}.
+ */
+ private final boolean allowMultipleTypes;
+ /**
+ * User defined key value strings for any metadata they want to associate with the group.
+ */
+ private final ImmutableMap properties;
+
+ public GroupProperties(SerializationFormat serializationFormat, SchemaValidationRules schemaValidationRules, boolean allowMultipleTypes) {
+ this(serializationFormat, schemaValidationRules, allowMultipleTypes, ImmutableMap.of());
+ }
+
+ public GroupProperties(SerializationFormat serializationFormat, SchemaValidationRules schemaValidationRules, boolean allowMultipleTypes, ImmutableMap properties) {
+ this.serializationFormat = serializationFormat;
+ this.schemaValidationRules = schemaValidationRules;
+ this.allowMultipleTypes = allowMultipleTypes;
+ this.properties = properties;
+ }
+
+ public static final class GroupPropertiesBuilder {
+ private SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.fullTransitive());
+ private boolean allowMultipleTypes = false;
+ private ImmutableMap properties = ImmutableMap.of();
+
+ public GroupPropertiesBuilder compatibility(Compatibility compatibility) {
+ this.schemaValidationRules = SchemaValidationRules.of(compatibility);
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
new file mode 100644
index 000000000..bc4ed9f62
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Encapsulates properties of a schema.
+ * {@link SchemaInfo#type} object type represented by the schema. This is used to identify the exact object type.
+ * If (ref: {@link GroupProperties#allowMultipleTypes}) is set to true, the group will allow multiple schemas to coexist.
+ * {@link SchemaInfo#serializationFormat} Serialization format.
+ * {@link SchemaInfo#schemaData} Schema as an array of 8-bit unsigned bytes. This is schema-type specific and to be consumed
+ * by schema-type specific parsers.
+ * {@link SchemaInfo#properties} A key value map of strings where user defined metadata can be recorded with schemas.
+ * This is not interpreted by the registry service or client and can be used by applications for sharing any additional
+ * application specific information with the schema.
+ */
+@Data
+@Builder
+public class SchemaInfo {
+ /**
+ * Identifies the object type that is represented by the schema.
+ */
+ private final String type;
+ /**
+ * Serialization format that this schema is intended to be used for.
+ */
+ private final SerializationFormat serializationFormat;
+ /**
+ * Schema as an array of 8-bit unsigned bytes.
+ */
+ private final ByteBuffer schemaData;
+ /**
+ * User defined key value strings that users can use to add any additional metadata to the schema.
+ */
+ private final ImmutableMap properties;
+
+ public SchemaInfo(String type, SerializationFormat serializationFormat, ByteBuffer schemaData, ImmutableMap properties) {
+ Preconditions.checkArgument(type != null);
+ Preconditions.checkArgument(serializationFormat != SerializationFormat.Any);
+ this.type = type;
+ this.serializationFormat = serializationFormat;
+ this.schemaData = schemaData;
+ this.properties = properties;
+ }
+
+ public static class SchemaInfoBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
new file mode 100644
index 000000000..c89670543
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+/**
+ * Base interface to define all schema validation rules. Schema validation rules are applied whenever new schemas are registered
+ * and only schemas that satisfy validation rules are accepted by the registry into the group.
+ */
+public interface SchemaValidationRule {
+ /**
+ * Name of the rule to identify it with.
+ *
+ * @return name of the rule.
+ */
+ String getName();
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
new file mode 100644
index 000000000..06f77fb09
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.base.Preconditions;
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Schema validation rules that are applied for checking if a schema is valid.
+ * This contains a set of rules {@link SchemaValidationRule}. Currently the only rule that is supported is {@link Compatibility}.
+ * The schema will be compared against one or more existing schemas in the group by checking it for satisfying each of the
+ * rules.
+ */
+@Data
+@Builder
+public class SchemaValidationRules {
+ /**
+ * Map of schema validation rule name to corresponding schema validation rule.
+ */
+ private final Map rules;
+
+ private SchemaValidationRules(Map rules) {
+ this.rules = rules;
+ }
+
+ /**
+ * Method to create a rule for compatibility.
+ *
+ * @param compatibility compatibility policy to be used.
+ * @return A singleton rules map containing the compatibility rule.
+ */
+ public static SchemaValidationRules of(Compatibility compatibility) {
+ return new SchemaValidationRules(Collections.singletonMap(compatibility.getName(), compatibility));
+ }
+
+ /**
+ * Method to create SchemaValidationRules from the list of supplied rules. If multiple same rule are present
+ * in the list then only the latest rule of each type is added to the Rules map.
+ * Currently the only rule supported is {@link Compatibility}.
+ * @param rules List of rules.
+ * @return SchemaValidationRules object.
+ */
+ public static SchemaValidationRules of(List rules) {
+ Preconditions.checkNotNull(rules);
+ Preconditions.checkArgument(rules.stream().allMatch(x -> x instanceof Compatibility), "Only compatibility rule is supported.");
+ return new SchemaValidationRules(rules.stream().collect(Collectors.toMap(SchemaValidationRule::getName, x -> x)));
+ }
+
+ public static class SchemaValidationRulesBuilder implements ObjectBuilder {
+ }
+
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
new file mode 100644
index 000000000..45e730cbf
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Object that encapsulates schemaInfo with its associated version.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class SchemaWithVersion {
+ /**
+ * Schema Information object.
+ */
+ private final SchemaInfo schemaInfo;
+ /**
+ * Version information object that identifies the corresponding schema object.
+ */
+ private final VersionInfo versionInfo;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
new file mode 100644
index 000000000..cecb9b257
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Different types of serialization formats used for serializing data.
+ * Registry supports Avro, Protobuf and Json serialization formats but any custom type could be used with the registry using custom type.
+ *
+ * If a serialization format is not present in the enum it can be specified using {@link SerializationFormat#custom} with {@link SerializationFormat#customTypeName}.
+ * Allowed values of {@link Compatibility} mode with custom type are AllowAny or DenyAll.
+ */
+
+public enum SerializationFormat {
+ Avro,
+ Protobuf,
+ Json,
+ Any,
+ Custom;
+
+ @Getter
+ @Setter(AccessLevel.PRIVATE)
+ private String customTypeName;
+
+ /**
+ * Method to define a custom serialization format with a custom name.
+ * @param customTypeName Custom type name.
+ * @return {@link SerializationFormat#Custom} with supplied custom type name.
+ */
+ public static SerializationFormat custom(String customTypeName) {
+ SerializationFormat type = SerializationFormat.Custom;
+ type.setCustomTypeName(customTypeName);
+ return type;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
new file mode 100644
index 000000000..c281e75e3
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Version information object that encapsulates properties that uniquely identify a specific version of a schema within a group.
+ *
+ * {@link VersionInfo#type} is same as {@link SchemaInfo#type} which represents the object type for which the version is computed.
+ * {@link VersionInfo#version} the registry assigned monotonically increasing version number for the schema for specific object type.
+ * Since the version number is per object type, so type and version number forms a unique pair.
+ * {@link VersionInfo#ordinal} Absolute ordinal of the schema for all schemas in the group. This uniquely identifies the
+ * version within a group.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class VersionInfo {
+ /**
+ * Object type which is declared in the corresponding {@link SchemaInfo#type} for the schemainfo that is identified
+ * by this version info.
+ */
+ private final String type;
+ /**
+ * A version number that identifies the position of schema among other schemas in the group that share the same 'type'.
+ */
+ private final int version;
+ /**
+ * A position identifier that uniquely identifies the schema within a group and represents the order in which this
+ * schema was included in the group.
+ */
+ private final int ordinal;
+
+ public static class VersionInfoBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
new file mode 100644
index 000000000..310f78ff8
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.
+ */
+@ApiModel(description = "Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.")
+
+public class AddedTo {
+ @JsonProperty("groups")
+ private Map groups = new HashMap();
+
+ public AddedTo groups(Map groups) {
+ this.groups = groups;
+ return this;
+ }
+
+ public AddedTo putGroupsItem(String key, VersionInfo groupsItem) {
+ this.groups.put(key, groupsItem);
+ return this;
+ }
+
+ /**
+ * Get groups
+ * @return groups
+ **/
+ @JsonProperty("groups")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public Map getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Map groups) {
+ this.groups = groups;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AddedTo addedTo = (AddedTo) o;
+ return Objects.equals(this.groups, addedTo.groups);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groups);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class AddedTo {\n");
+
+ sb.append(" groups: ").append(toIndentedString(groups)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
new file mode 100644
index 000000000..5f101741a
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for canRead api.
+ */
+@ApiModel(description = "Response object for canRead api.")
+
+public class CanRead {
+ @JsonProperty("compatible")
+ private Boolean compatible = null;
+
+ public CanRead compatible(Boolean compatible) {
+ this.compatible = compatible;
+ return this;
+ }
+
+ /**
+ * Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.
+ * @return compatible
+ **/
+ @JsonProperty("compatible")
+ @ApiModelProperty(required = true, value = "Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.")
+ @NotNull
+ public Boolean isCompatible() {
+ return compatible;
+ }
+
+ public void setCompatible(Boolean compatible) {
+ this.compatible = compatible;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CanRead canRead = (CanRead) o;
+ return Objects.equals(this.compatible, canRead.compatible);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(compatible);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CanRead {\n");
+
+ sb.append(" compatible: ").append(toIndentedString(compatible)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
new file mode 100644
index 000000000..96c10bacc
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for listCodecTypes.
+ */
+@ApiModel(description = "Response object for listCodecTypes.")
+
+public class CodecTypesList {
+ @JsonProperty("codecTypes")
+ private List codecTypes = null;
+
+ public CodecTypesList codecTypes(List codecTypes) {
+ this.codecTypes = codecTypes;
+ return this;
+ }
+
+ public CodecTypesList addCodecTypesItem(String codecTypesItem) {
+ if (this.codecTypes == null) {
+ this.codecTypes = new ArrayList();
+ }
+ this.codecTypes.add(codecTypesItem);
+ return this;
+ }
+
+ /**
+ * List of codecTypes.
+ * @return codecTypes
+ **/
+ @JsonProperty("codecTypes")
+ @ApiModelProperty(value = "List of codecTypes.")
+ public List getCodecTypes() {
+ return codecTypes;
+ }
+
+ public void setCodecTypes(List codecTypes) {
+ this.codecTypes = codecTypes;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CodecTypesList codecTypesList = (CodecTypesList) o;
+ return Objects.equals(this.codecTypes, codecTypesList.codecTypes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(codecTypes);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CodecTypesList {\n");
+
+ sb.append(" codecTypes: ").append(toIndentedString(codecTypes)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
new file mode 100644
index 000000000..459893324
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
@@ -0,0 +1,216 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Schema Compatibility validation rule.
+ */
+@ApiModel(description = "Schema Compatibility validation rule.")
+
+public class Compatibility {
+ @JsonProperty("name")
+ private String name = null;
+
+ /**
+ * Compatibility policy enum.
+ */
+ public enum PolicyEnum {
+ ALLOWANY("AllowAny"),
+
+ DENYALL("DenyAll"),
+
+ BACKWARD("Backward"),
+
+ FORWARD("Forward"),
+
+ FORWARDTRANSITIVE("ForwardTransitive"),
+
+ BACKWARDTRANSITIVE("BackwardTransitive"),
+
+ BACKWARDTILL("BackwardTill"),
+
+ FORWARDTILL("ForwardTill"),
+
+ BACKWARDANDFORWARDTILL("BackwardAndForwardTill"),
+
+ FULL("Full"),
+
+ FULLTRANSITIVE("FullTransitive");
+
+ private String value;
+
+ PolicyEnum(String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+ @JsonCreator
+ public static PolicyEnum fromValue(String text) {
+ for (PolicyEnum b : PolicyEnum.values()) {
+ if (String.valueOf(b.value).equals(text)) {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ @JsonProperty("policy")
+ private PolicyEnum policy = null;
+
+ @JsonProperty("backwardTill")
+ private VersionInfo backwardTill = null;
+
+ @JsonProperty("forwardTill")
+ private VersionInfo forwardTill = null;
+
+ public Compatibility name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be \"Compatibility\".
+ * @return name
+ **/
+ @JsonProperty("name")
+ @ApiModelProperty(required = true, value = "Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be \"Compatibility\".")
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Compatibility policy(PolicyEnum policy) {
+ this.policy = policy;
+ return this;
+ }
+
+ /**
+ * Compatibility policy enum.
+ * @return policy
+ **/
+ @JsonProperty("policy")
+ @ApiModelProperty(required = true, value = "Compatibility policy enum.")
+ @NotNull
+ public PolicyEnum getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(PolicyEnum policy) {
+ this.policy = policy;
+ }
+
+ public Compatibility backwardTill(VersionInfo backwardTill) {
+ this.backwardTill = backwardTill;
+ return this;
+ }
+
+ /**
+ * Version for backward till if policy is BackwardTill or BackwardAndForwardTill.
+ * @return backwardTill
+ **/
+ @JsonProperty("backwardTill")
+ @ApiModelProperty(value = "Version for backward till if policy is BackwardTill or BackwardAndForwardTill.")
+ public VersionInfo getBackwardTill() {
+ return backwardTill;
+ }
+
+ public void setBackwardTill(VersionInfo backwardTill) {
+ this.backwardTill = backwardTill;
+ }
+
+ public Compatibility forwardTill(VersionInfo forwardTill) {
+ this.forwardTill = forwardTill;
+ return this;
+ }
+
+ /**
+ * Version for forward till if policy is ForwardTill or BackwardAndForwardTill.
+ * @return forwardTill
+ **/
+ @JsonProperty("forwardTill")
+ @ApiModelProperty(value = "Version for forward till if policy is ForwardTill or BackwardAndForwardTill.")
+ public VersionInfo getForwardTill() {
+ return forwardTill;
+ }
+
+ public void setForwardTill(VersionInfo forwardTill) {
+ this.forwardTill = forwardTill;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Compatibility compatibility = (Compatibility) o;
+ return Objects.equals(this.name, compatibility.name) &&
+ Objects.equals(this.policy, compatibility.policy) &&
+ Objects.equals(this.backwardTill, compatibility.backwardTill) &&
+ Objects.equals(this.forwardTill, compatibility.forwardTill);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, policy, backwardTill, forwardTill);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class Compatibility {\n");
+
+ sb.append(" name: ").append(toIndentedString(name)).append("\n");
+ sb.append(" policy: ").append(toIndentedString(policy)).append("\n");
+ sb.append(" backwardTill: ").append(toIndentedString(backwardTill)).append("\n");
+ sb.append(" forwardTill: ").append(toIndentedString(forwardTill)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
new file mode 100644
index 000000000..22d2b8b29
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * CreateGroupRequest
+ */
+
+public class CreateGroupRequest {
+ @JsonProperty("groupName")
+ private String groupName = null;
+
+ @JsonProperty("groupProperties")
+ private GroupProperties groupProperties = null;
+
+ public CreateGroupRequest groupName(String groupName) {
+ this.groupName = groupName;
+ return this;
+ }
+
+ /**
+ * Get groupName
+ * @return groupName
+ **/
+ @JsonProperty("groupName")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public void setGroupName(String groupName) {
+ this.groupName = groupName;
+ }
+
+ public CreateGroupRequest groupProperties(GroupProperties groupProperties) {
+ this.groupProperties = groupProperties;
+ return this;
+ }
+
+ /**
+ * Get groupProperties
+ * @return groupProperties
+ **/
+ @JsonProperty("groupProperties")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public GroupProperties getGroupProperties() {
+ return groupProperties;
+ }
+
+ public void setGroupProperties(GroupProperties groupProperties) {
+ this.groupProperties = groupProperties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CreateGroupRequest createGroupRequest = (CreateGroupRequest) o;
+ return Objects.equals(this.groupName, createGroupRequest.groupName) &&
+ Objects.equals(this.groupProperties, createGroupRequest.groupProperties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groupName, groupProperties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CreateGroupRequest {\n");
+
+ sb.append(" groupName: ").append(toIndentedString(groupName)).append("\n");
+ sb.append(" groupProperties: ").append(toIndentedString(groupProperties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
new file mode 100644
index 000000000..50f95270c
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Encoding id that uniquely identifies a schema version and codec type pair.
+ */
+@ApiModel(description = "Encoding id that uniquely identifies a schema version and codec type pair.")
+
+public class EncodingId {
+ @JsonProperty("encodingId")
+ private Integer encodingId = null;
+
+ public EncodingId encodingId(Integer encodingId) {
+ this.encodingId = encodingId;
+ return this;
+ }
+
+ /**
+ * encoding id generated by service.
+ * @return encodingId
+ **/
+ @JsonProperty("encodingId")
+ @ApiModelProperty(required = true, value = "encoding id generated by service.")
+ @NotNull
+ public Integer getEncodingId() {
+ return encodingId;
+ }
+
+ public void setEncodingId(Integer encodingId) {
+ this.encodingId = encodingId;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EncodingId encodingId = (EncodingId) o;
+ return Objects.equals(this.encodingId, encodingId.encodingId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(encodingId);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EncodingId {\n");
+
+ sb.append(" encodingId: ").append(toIndentedString(encodingId)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
new file mode 100644
index 000000000..1276ec038
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
@@ -0,0 +1,144 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Encoding information object that resolves the schema version and codec type used for corresponding encoding id.
+ */
+@ApiModel(description = "Encoding information object that resolves the schema version and codec type used for corresponding encoding id.")
+
+public class EncodingInfo {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("versionInfo")
+ private VersionInfo versionInfo = null;
+
+ @JsonProperty("codecType")
+ private String codecType = null;
+
+ public EncodingInfo schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information object.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information object.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public EncodingInfo versionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ return this;
+ }
+
+ /**
+ * Version information object.
+ * @return versionInfo
+ **/
+ @JsonProperty("versionInfo")
+ @ApiModelProperty(required = true, value = "Version information object.")
+ @NotNull
+ public VersionInfo getVersionInfo() {
+ return versionInfo;
+ }
+
+ public void setVersionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ }
+
+ public EncodingInfo codecType(String codecType) {
+ this.codecType = codecType;
+ return this;
+ }
+
+ /**
+ * Codec type.
+ * @return codecType
+ **/
+ @JsonProperty("codecType")
+ @ApiModelProperty(required = true, value = "Codec type.")
+ @NotNull
+ public String getCodecType() {
+ return codecType;
+ }
+
+ public void setCodecType(String codecType) {
+ this.codecType = codecType;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EncodingInfo encodingInfo = (EncodingInfo) o;
+ return Objects.equals(this.schemaInfo, encodingInfo.schemaInfo) &&
+ Objects.equals(this.versionInfo, encodingInfo.versionInfo) &&
+ Objects.equals(this.codecType, encodingInfo.codecType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, versionInfo, codecType);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EncodingInfo {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" versionInfo: ").append(toIndentedString(versionInfo)).append("\n");
+ sb.append(" codecType: ").append(toIndentedString(codecType)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
new file mode 100644
index 000000000..6376af636
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * GetEncodingIdRequest
+ */
+
+public class GetEncodingIdRequest {
+ @JsonProperty("versionInfo")
+ private VersionInfo versionInfo = null;
+
+ @JsonProperty("codecType")
+ private String codecType = null;
+
+ public GetEncodingIdRequest versionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ return this;
+ }
+
+ /**
+ * Get versionInfo
+ * @return versionInfo
+ **/
+ @JsonProperty("versionInfo")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public VersionInfo getVersionInfo() {
+ return versionInfo;
+ }
+
+ public void setVersionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ }
+
+ public GetEncodingIdRequest codecType(String codecType) {
+ this.codecType = codecType;
+ return this;
+ }
+
+ /**
+ * Get codecType
+ * @return codecType
+ **/
+ @JsonProperty("codecType")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public String getCodecType() {
+ return codecType;
+ }
+
+ public void setCodecType(String codecType) {
+ this.codecType = codecType;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GetEncodingIdRequest getEncodingIdRequest = (GetEncodingIdRequest) o;
+ return Objects.equals(this.versionInfo, getEncodingIdRequest.versionInfo) &&
+ Objects.equals(this.codecType, getEncodingIdRequest.codecType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(versionInfo, codecType);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GetEncodingIdRequest {\n");
+
+ sb.append(" versionInfo: ").append(toIndentedString(versionInfo)).append("\n");
+ sb.append(" codecType: ").append(toIndentedString(codecType)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
new file mode 100644
index 000000000..cf195ba93
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * GroupHistory
+ */
+
+public class GroupHistory {
+ @JsonProperty("history")
+ private List history = null;
+
+ public GroupHistory history(List history) {
+ this.history = history;
+ return this;
+ }
+
+ public GroupHistory addHistoryItem(GroupHistoryRecord historyItem) {
+ if (this.history == null) {
+ this.history = new ArrayList();
+ }
+ this.history.add(historyItem);
+ return this;
+ }
+
+ /**
+ * Chronological list of Group History records.
+ * @return history
+ **/
+ @JsonProperty("history")
+ @ApiModelProperty(value = "Chronological list of Group History records.")
+ public List getHistory() {
+ return history;
+ }
+
+ public void setHistory(List history) {
+ this.history = history;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupHistory groupHistory = (GroupHistory) o;
+ return Objects.equals(this.history, groupHistory.history);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(history);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupHistory {\n");
+
+ sb.append(" history: ").append(toIndentedString(history)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
new file mode 100644
index 000000000..6d7dd7476
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
@@ -0,0 +1,194 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.
+ */
+@ApiModel(description = "Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.")
+
+public class GroupHistoryRecord {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("version")
+ private VersionInfo version = null;
+
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ @JsonProperty("timestamp")
+ private Long timestamp = null;
+
+ @JsonProperty("schemaString")
+ private String schemaString = null;
+
+ public GroupHistoryRecord schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information object.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information object.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public GroupHistoryRecord version(VersionInfo version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Schema version information object.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Schema version information object.")
+ @NotNull
+ public VersionInfo getVersion() {
+ return version;
+ }
+
+ public void setVersion(VersionInfo version) {
+ this.version = version;
+ }
+
+ public GroupHistoryRecord validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Schema validation rules applied.
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(required = true, value = "Schema validation rules applied.")
+ @NotNull
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+ public GroupHistoryRecord timestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ return this;
+ }
+
+ /**
+ * Timestamp when the schema was added.
+ * @return timestamp
+ **/
+ @JsonProperty("timestamp")
+ @ApiModelProperty(required = true, value = "Timestamp when the schema was added.")
+ @NotNull
+ public Long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public GroupHistoryRecord schemaString(String schemaString) {
+ this.schemaString = schemaString;
+ return this;
+ }
+
+ /**
+ * Schema as json string for serialization formats that registry service understands.
+ * @return schemaString
+ **/
+ @JsonProperty("schemaString")
+ @ApiModelProperty(value = "Schema as json string for serialization formats that registry service understands.")
+ public String getSchemaString() {
+ return schemaString;
+ }
+
+ public void setSchemaString(String schemaString) {
+ this.schemaString = schemaString;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupHistoryRecord groupHistoryRecord = (GroupHistoryRecord) o;
+ return Objects.equals(this.schemaInfo, groupHistoryRecord.schemaInfo) &&
+ Objects.equals(this.version, groupHistoryRecord.version) &&
+ Objects.equals(this.validationRules, groupHistoryRecord.validationRules) &&
+ Objects.equals(this.timestamp, groupHistoryRecord.timestamp) &&
+ Objects.equals(this.schemaString, groupHistoryRecord.schemaString);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, version, validationRules, timestamp, schemaString);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupHistoryRecord {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append(" timestamp: ").append(toIndentedString(timestamp)).append("\n");
+ sb.append(" schemaString: ").append(toIndentedString(schemaString)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
new file mode 100644
index 000000000..4bbb60b12
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
@@ -0,0 +1,179 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Metadata for a group.
+ */
+@ApiModel(description = "Metadata for a group.")
+
+public class GroupProperties {
+ @JsonProperty("serializationFormat")
+ private SerializationFormat serializationFormat = null;
+
+ @JsonProperty("schemaValidationRules")
+ private SchemaValidationRules schemaValidationRules = null;
+
+ @JsonProperty("allowMultipleTypes")
+ private Boolean allowMultipleTypes = null;
+
+ @JsonProperty("properties")
+ private Map properties = null;
+
+ public GroupProperties serializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * serialization format for the group.
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "serialization format for the group.")
+ @NotNull
+ public SerializationFormat getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public GroupProperties schemaValidationRules(SchemaValidationRules schemaValidationRules) {
+ this.schemaValidationRules = schemaValidationRules;
+ return this;
+ }
+
+ /**
+ * Validation rules to apply while registering new schema.
+ * @return schemaValidationRules
+ **/
+ @JsonProperty("schemaValidationRules")
+ @ApiModelProperty(required = true, value = "Validation rules to apply while registering new schema.")
+ @NotNull
+ public SchemaValidationRules getSchemaValidationRules() {
+ return schemaValidationRules;
+ }
+
+ public void setSchemaValidationRules(SchemaValidationRules schemaValidationRules) {
+ this.schemaValidationRules = schemaValidationRules;
+ }
+
+ public GroupProperties allowMultipleTypes(Boolean allowMultipleTypes) {
+ this.allowMultipleTypes = allowMultipleTypes;
+ return this;
+ }
+
+ /**
+ * Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.
+ * @return allowMultipleTypes
+ **/
+ @JsonProperty("allowMultipleTypes")
+ @ApiModelProperty(required = true, value = "Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.")
+ @NotNull
+ public Boolean isAllowMultipleTypes() {
+ return allowMultipleTypes;
+ }
+
+ public void setAllowMultipleTypes(Boolean allowMultipleTypes) {
+ this.allowMultipleTypes = allowMultipleTypes;
+ }
+
+ public GroupProperties properties(Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public GroupProperties putPropertiesItem(String key, String propertiesItem) {
+ if (this.properties == null) {
+ this.properties = new HashMap();
+ }
+ this.properties.put(key, propertiesItem);
+ return this;
+ }
+
+ /**
+ * User defined Key value strings.
+ * @return properties
+ **/
+ @JsonProperty("properties")
+ @ApiModelProperty(value = "User defined Key value strings.")
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupProperties groupProperties = (GroupProperties) o;
+ return Objects.equals(this.serializationFormat, groupProperties.serializationFormat) &&
+ Objects.equals(this.schemaValidationRules, groupProperties.schemaValidationRules) &&
+ Objects.equals(this.allowMultipleTypes, groupProperties.allowMultipleTypes) &&
+ Objects.equals(this.properties, groupProperties.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(serializationFormat, schemaValidationRules, allowMultipleTypes, properties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupProperties {\n");
+
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" schemaValidationRules: ").append(toIndentedString(schemaValidationRules)).append("\n");
+ sb.append(" allowMultipleTypes: ").append(toIndentedString(allowMultipleTypes)).append("\n");
+ sb.append(" properties: ").append(toIndentedString(properties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
new file mode 100644
index 000000000..966b6898f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
@@ -0,0 +1,128 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Map of Group names to group properties. For partially created groups, the group properties may be null.
+ */
+@ApiModel(description = "Map of Group names to group properties. For partially created groups, the group properties may be null.")
+
+public class ListGroupsResponse {
+ @JsonProperty("groups")
+ private Map groups = null;
+
+ @JsonProperty("continuationToken")
+ private String continuationToken = null;
+
+ public ListGroupsResponse groups(Map groups) {
+ this.groups = groups;
+ return this;
+ }
+
+ public ListGroupsResponse putGroupsItem(String key, GroupProperties groupsItem) {
+ if (this.groups == null) {
+ this.groups = new HashMap();
+ }
+ this.groups.put(key, groupsItem);
+ return this;
+ }
+
+ /**
+ * Get groups
+ * @return groups
+ **/
+ @JsonProperty("groups")
+ @ApiModelProperty(value = "")
+ public Map getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Map groups) {
+ this.groups = groups;
+ }
+
+ public ListGroupsResponse continuationToken(String continuationToken) {
+ this.continuationToken = continuationToken;
+ return this;
+ }
+
+ /**
+ * Continuation token to identify the position of last group in the response.
+ * @return continuationToken
+ **/
+ @JsonProperty("continuationToken")
+ @ApiModelProperty(required = true, value = "Continuation token to identify the position of last group in the response.")
+ @NotNull
+ public String getContinuationToken() {
+ return continuationToken;
+ }
+
+ public void setContinuationToken(String continuationToken) {
+ this.continuationToken = continuationToken;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ListGroupsResponse listGroupsResponse = (ListGroupsResponse) o;
+ return Objects.equals(this.groups, listGroupsResponse.groups) &&
+ Objects.equals(this.continuationToken, listGroupsResponse.continuationToken);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groups, continuationToken);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class ListGroupsResponse {\n");
+
+ sb.append(" groups: ").append(toIndentedString(groups)).append("\n");
+ sb.append(" continuationToken: ").append(toIndentedString(continuationToken)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
new file mode 100644
index 000000000..2be4282ab
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
@@ -0,0 +1,179 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Arrays;
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Schema information object that encapsulates various properties of a schema.
+ */
+@ApiModel(description = "Schema information object that encapsulates various properties of a schema.")
+
+public class SchemaInfo {
+ @JsonProperty("type")
+ private String type = null;
+
+ @JsonProperty("serializationFormat")
+ private SerializationFormat serializationFormat = null;
+
+ @JsonProperty("schemaData")
+ private byte[] schemaData = null;
+
+ @JsonProperty("properties")
+ private Map properties = null;
+
+ public SchemaInfo type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Name of the schema. This identifies the type of object the schema payload represents.
+ * @return type
+ **/
+ @JsonProperty("type")
+ @ApiModelProperty(required = true, value = "Name of the schema. This identifies the type of object the schema payload represents.")
+ @NotNull
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public SchemaInfo serializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * Type of schema.
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "Type of schema.")
+ @NotNull
+ public SerializationFormat getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public SchemaInfo schemaData(byte[] schemaData) {
+ this.schemaData = schemaData;
+ return this;
+ }
+
+ /**
+ * Base64 encoded string for binary data for schema.
+ * @return schemaData
+ **/
+ @JsonProperty("schemaData")
+ @ApiModelProperty(required = true, value = "Base64 encoded string for binary data for schema.")
+ @NotNull
+ public byte[] getSchemaData() {
+ return schemaData;
+ }
+
+ public void setSchemaData(byte[] schemaData) {
+ this.schemaData = schemaData;
+ }
+
+ public SchemaInfo properties(Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public SchemaInfo putPropertiesItem(String key, String propertiesItem) {
+ if (this.properties == null) {
+ this.properties = new HashMap();
+ }
+ this.properties.put(key, propertiesItem);
+ return this;
+ }
+
+ /**
+ * User defined key value strings.
+ * @return properties
+ **/
+ @JsonProperty("properties")
+ @ApiModelProperty(value = "User defined key value strings.")
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaInfo schemaInfo = (SchemaInfo) o;
+ return Objects.equals(this.type, schemaInfo.type) &&
+ Objects.equals(this.serializationFormat, schemaInfo.serializationFormat) &&
+ Arrays.equals(this.schemaData, schemaInfo.schemaData) &&
+ Objects.equals(this.properties, schemaInfo.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, serializationFormat, schemaData, properties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaInfo {\n");
+
+ sb.append(" type: ").append(toIndentedString(type)).append("\n");
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" schemaData: ").append(toIndentedString(schemaData)).append("\n");
+ sb.append(" properties: ").append(toIndentedString(properties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
new file mode 100644
index 000000000..9fb9ee11d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Schema validation rule base class.
+ */
+@ApiModel(description = "Schema validation rule base class.")
+
+public class SchemaValidationRule {
+ @JsonProperty("rule")
+ private Object rule = null;
+
+ public SchemaValidationRule rule(Object rule) {
+ this.rule = rule;
+ return this;
+ }
+
+ /**
+ * Specific schema validation rule. The only rule we have presently is Compatibility. The \"name\" is used to identify specific Rule type. The only rule supported in this is Compatibility.
+ * @return rule
+ **/
+ @JsonProperty("rule")
+ @ApiModelProperty(required = true, value = "Specific schema validation rule. The only rule we have presently is Compatibility. The \"name\" is used to identify specific Rule type. The only rule supported in this is Compatibility.")
+ @NotNull
+ public Object getRule() {
+ return rule;
+ }
+
+ public void setRule(Object rule) {
+ this.rule = rule;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaValidationRule schemaValidationRule = (SchemaValidationRule) o;
+ return Objects.equals(this.rule, schemaValidationRule.rule);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rule);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaValidationRule {\n");
+
+ sb.append(" rule: ").append(toIndentedString(rule)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
new file mode 100644
index 000000000..0f9d7af0b
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
@@ -0,0 +1,103 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRule;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.
+ */
+@ApiModel(description = "Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.")
+
+public class SchemaValidationRules {
+ @JsonProperty("rules")
+ private Map rules = null;
+
+ public SchemaValidationRules rules(Map rules) {
+ this.rules = rules;
+ return this;
+ }
+
+ public SchemaValidationRules putRulesItem(String key, SchemaValidationRule rulesItem) {
+ if (this.rules == null) {
+ this.rules = new HashMap();
+ }
+ this.rules.put(key, rulesItem);
+ return this;
+ }
+
+ /**
+ * Get rules
+ * @return rules
+ **/
+ @JsonProperty("rules")
+ @ApiModelProperty(value = "")
+ public Map getRules() {
+ return rules;
+ }
+
+ public void setRules(Map rules) {
+ this.rules = rules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaValidationRules schemaValidationRules = (SchemaValidationRules) o;
+ return Objects.equals(this.rules, schemaValidationRules.rules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaValidationRules {\n");
+
+ sb.append(" rules: ").append(toIndentedString(rules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
new file mode 100644
index 000000000..6be73a69d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
@@ -0,0 +1,102 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * List of schemas with their versions.
+ */
+@ApiModel(description = "List of schemas with their versions.")
+
+public class SchemaVersionsList {
+ @JsonProperty("schemas")
+ private List schemas = null;
+
+ public SchemaVersionsList schemas(List schemas) {
+ this.schemas = schemas;
+ return this;
+ }
+
+ public SchemaVersionsList addSchemasItem(SchemaWithVersion schemasItem) {
+ if (this.schemas == null) {
+ this.schemas = new ArrayList();
+ }
+ this.schemas.add(schemasItem);
+ return this;
+ }
+
+ /**
+ * List of schemas with their versions.
+ * @return schemas
+ **/
+ @JsonProperty("schemas")
+ @ApiModelProperty(value = "List of schemas with their versions.")
+ public List getSchemas() {
+ return schemas;
+ }
+
+ public void setSchemas(List schemas) {
+ this.schemas = schemas;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaVersionsList schemaVersionsList = (SchemaVersionsList) o;
+ return Objects.equals(this.schemas, schemaVersionsList.schemas);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemas);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaVersionsList {\n");
+
+ sb.append(" schemas: ").append(toIndentedString(schemas)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
new file mode 100644
index 000000000..bc0687fff
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
@@ -0,0 +1,119 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.
+ */
+@ApiModel(description = "Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.")
+
+public class SchemaWithVersion {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("version")
+ private VersionInfo version = null;
+
+ public SchemaWithVersion schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public SchemaWithVersion version(VersionInfo version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Version information.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Version information.")
+ @NotNull
+ public VersionInfo getVersion() {
+ return version;
+ }
+
+ public void setVersion(VersionInfo version) {
+ this.version = version;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaWithVersion schemaWithVersion = (SchemaWithVersion) o;
+ return Objects.equals(this.schemaInfo, schemaWithVersion.schemaInfo) &&
+ Objects.equals(this.version, schemaWithVersion.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, version);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaWithVersion {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
new file mode 100644
index 000000000..bc980cbd6
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
@@ -0,0 +1,154 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.
+ */
+@ApiModel(description = "Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.")
+
+public class SerializationFormat {
+ /**
+ * Gets or Sets serializationFormat
+ */
+ public enum SerializationFormatEnum {
+ AVRO("Avro"),
+
+ PROTOBUF("Protobuf"),
+
+ JSON("Json"),
+
+ ANY("Any"),
+
+ CUSTOM("Custom");
+
+ private String value;
+
+ SerializationFormatEnum(String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+ @JsonCreator
+ public static SerializationFormatEnum fromValue(String text) {
+ for (SerializationFormatEnum b : SerializationFormatEnum.values()) {
+ if (String.valueOf(b.value).equals(text)) {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ @JsonProperty("serializationFormat")
+ private SerializationFormatEnum serializationFormat = null;
+
+ @JsonProperty("customTypeName")
+ private String customTypeName = null;
+
+ public SerializationFormat serializationFormat(SerializationFormatEnum serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * Get serializationFormat
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SerializationFormatEnum getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormatEnum serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public SerializationFormat customTypeName(String customTypeName) {
+ this.customTypeName = customTypeName;
+ return this;
+ }
+
+ /**
+ * Get customTypeName
+ * @return customTypeName
+ **/
+ @JsonProperty("customTypeName")
+ @ApiModelProperty(value = "")
+ public String getCustomTypeName() {
+ return customTypeName;
+ }
+
+ public void setCustomTypeName(String customTypeName) {
+ this.customTypeName = customTypeName;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SerializationFormat serializationFormat = (SerializationFormat) o;
+ return Objects.equals(this.serializationFormat, serializationFormat.serializationFormat) &&
+ Objects.equals(this.customTypeName, serializationFormat.customTypeName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(serializationFormat, customTypeName);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SerializationFormat {\n");
+
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" customTypeName: ").append(toIndentedString(customTypeName)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
new file mode 100644
index 000000000..92cdef2d9
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
@@ -0,0 +1,116 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * UpdateValidationRulesRequest
+ */
+
+public class UpdateValidationRulesRequest {
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ @JsonProperty("previousRules")
+ private SchemaValidationRules previousRules = null;
+
+ public UpdateValidationRulesRequest validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Get validationRules
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+ public UpdateValidationRulesRequest previousRules(SchemaValidationRules previousRules) {
+ this.previousRules = previousRules;
+ return this;
+ }
+
+ /**
+ * Get previousRules
+ * @return previousRules
+ **/
+ @JsonProperty("previousRules")
+ @ApiModelProperty(value = "")
+ public SchemaValidationRules getPreviousRules() {
+ return previousRules;
+ }
+
+ public void setPreviousRules(SchemaValidationRules previousRules) {
+ this.previousRules = previousRules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UpdateValidationRulesRequest updateValidationRulesRequest = (UpdateValidationRulesRequest) o;
+ return Objects.equals(this.validationRules, updateValidationRulesRequest.validationRules) &&
+ Objects.equals(this.previousRules, updateValidationRulesRequest.previousRules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(validationRules, previousRules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class UpdateValidationRulesRequest {\n");
+
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append(" previousRules: ").append(toIndentedString(previousRules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
new file mode 100644
index 000000000..bde7b3f10
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for validateSchema api.
+ */
+@ApiModel(description = "Response object for validateSchema api.")
+
+public class Valid {
+ @JsonProperty("valid")
+ private Boolean valid = null;
+
+ public Valid valid(Boolean valid) {
+ this.valid = valid;
+ return this;
+ }
+
+ /**
+ * Whether given schema is valid with respect to existing group schemas against the configured validation rules.
+ * @return valid
+ **/
+ @JsonProperty("valid")
+ @ApiModelProperty(required = true, value = "Whether given schema is valid with respect to existing group schemas against the configured validation rules.")
+ @NotNull
+ public Boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(Boolean valid) {
+ this.valid = valid;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Valid valid = (Valid) o;
+ return Objects.equals(this.valid, valid.valid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(valid);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class Valid {\n");
+
+ sb.append(" valid: ").append(toIndentedString(valid)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
new file mode 100644
index 000000000..5daa183df
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * ValidateRequest
+ */
+
+public class ValidateRequest {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ public ValidateRequest schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Get schemaInfo
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public ValidateRequest validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Get validationRules
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(value = "")
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ValidateRequest validateRequest = (ValidateRequest) o;
+ return Objects.equals(this.schemaInfo, validateRequest.schemaInfo) &&
+ Objects.equals(this.validationRules, validateRequest.validationRules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, validationRules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class ValidateRequest {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
new file mode 100644
index 000000000..9b4c2603d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
@@ -0,0 +1,142 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Version information object.
+ */
+@ApiModel(description = "Version information object.")
+
+public class VersionInfo {
+ @JsonProperty("type")
+ private String type = null;
+
+ @JsonProperty("version")
+ private Integer version = null;
+
+ @JsonProperty("ordinal")
+ private Integer ordinal = null;
+
+ public VersionInfo type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.
+ * @return type
+ **/
+ @JsonProperty("type")
+ @ApiModelProperty(required = true, value = "Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.")
+ @NotNull
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public VersionInfo version(Integer version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.")
+ @NotNull
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ public VersionInfo ordinal(Integer ordinal) {
+ this.ordinal = ordinal;
+ return this;
+ }
+
+ /**
+ * Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.
+ * @return ordinal
+ **/
+ @JsonProperty("ordinal")
+ @ApiModelProperty(required = true, value = "Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.")
+ @NotNull
+ public Integer getOrdinal() {
+ return ordinal;
+ }
+
+ public void setOrdinal(Integer ordinal) {
+ this.ordinal = ordinal;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ VersionInfo versionInfo = (VersionInfo) o;
+ return Objects.equals(this.type, versionInfo.type) &&
+ Objects.equals(this.version, versionInfo.version) &&
+ Objects.equals(this.ordinal, versionInfo.ordinal);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, version, ordinal);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class VersionInfo {\n");
+
+ sb.append(" type: ").append(toIndentedString(type)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append(" ordinal: ").append(toIndentedString(ordinal)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
new file mode 100644
index 000000000..096b7c1d1
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
@@ -0,0 +1,10 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class ApiException extends Exception{
+ private int code;
+ public ApiException (int code, String msg) {
+ super(msg);
+ this.code = code;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
new file mode 100644
index 000000000..1ad2cce34
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
@@ -0,0 +1,22 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import java.io.IOException;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+
+
+public class ApiOriginFilter implements javax.servlet.Filter {
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ HttpServletResponse res = (HttpServletResponse) response;
+ res.addHeader("Access-Control-Allow-Origin", "*");
+ res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
+ res.addHeader("Access-Control-Allow-Headers", "Content-Type");
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {}
+
+ public void init(FilterConfig filterConfig) throws ServletException {}
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
new file mode 100644
index 000000000..47e3f5d76
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
@@ -0,0 +1,69 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import javax.xml.bind.annotation.XmlTransient;
+
+@javax.xml.bind.annotation.XmlRootElement
+
+public class ApiResponseMessage {
+ public static final int ERROR = 1;
+ public static final int WARNING = 2;
+ public static final int INFO = 3;
+ public static final int OK = 4;
+ public static final int TOO_BUSY = 5;
+
+ int code;
+ String type;
+ String message;
+
+ public ApiResponseMessage(){}
+
+ public ApiResponseMessage(int code, String message){
+ this.code = code;
+ switch(code){
+ case ERROR:
+ setType("error");
+ break;
+ case WARNING:
+ setType("warning");
+ break;
+ case INFO:
+ setType("info");
+ break;
+ case OK:
+ setType("ok");
+ break;
+ case TOO_BUSY:
+ setType("too busy");
+ break;
+ default:
+ setType("unknown");
+ break;
+ }
+ this.message = message;
+ }
+
+ @XmlTransient
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
new file mode 100644
index 000000000..deb52b674
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
@@ -0,0 +1,31 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.swagger.jaxrs.config.SwaggerContextService;
+import io.swagger.models.*;
+
+import io.swagger.models.auth.*;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+public class Bootstrap extends HttpServlet {
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ Info info = new Info()
+ .title("Swagger Server")
+ .description("REST APIs for Pravega Schema Registry.")
+ .termsOfService("")
+ .contact(new Contact()
+ .email(""))
+ .license(new License()
+ .name("Apache 2.0")
+ .url("http://www.apache.org/licenses/LICENSE-2.0"));
+
+ ServletContext context = config.getServletContext();
+ Swagger swagger = new Swagger().info(info);
+
+ new SwaggerContextService().withServletConfig(config).updateSwagger(swagger);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
new file mode 100644
index 000000000..16db9f378
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
@@ -0,0 +1,412 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.GroupsApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.factories.GroupsApiServiceFactory;
+
+import io.swagger.annotations.ApiParam;
+import io.swagger.jaxrs.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.Map;
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.servlet.ServletConfig;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.*;
+import javax.validation.constraints.*;
+
+@Path("/groups")
+
+
+@io.swagger.annotations.Api(description = "the groups API")
+
+public class GroupsApi {
+ private final GroupsApiService delegate;
+
+ public GroupsApi(@Context ServletConfig servletContext) {
+ GroupsApiService delegate = null;
+
+ if (servletContext != null) {
+ String implClass = servletContext.getInitParameter("GroupsApi.implementation");
+ if (implClass != null && !"".equals(implClass.trim())) {
+ try {
+ delegate = (GroupsApiService) Class.forName(implClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ if (delegate == null) {
+ delegate = GroupsApiServiceFactory.getGroupsApi();
+ }
+
+ this.delegate = delegate;
+ }
+
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while registering codectype to a Group", response = Void.class) })
+ public Response addCodecType(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "The codecType" ,required=true) String codecType
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.addCodecType(groupName,codecType,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while adding schema to group", response = Void.class) })
+ public Response addSchema(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Add new schema to group" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.addSchema(groupName,schemaInfo,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class) })
+ public Response canRead(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules." ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.canRead(groupName,schemaInfo,securityContext);
+ }
+ @POST
+
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class) })
+ public Response createGroup(@ApiParam(value = "The Group configuration" ,required=true) CreateGroupRequest createGroupRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.createGroup(createGroupRequest,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}")
+
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class) })
+ public Response deleteGroup(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteGroup(groupName,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class) })
+ public Response deleteSchemaVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type",required=true) @PathParam("type") String type
+,@ApiParam(value = "Version number",required=true) @PathParam("version") Integer version
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteSchemaVersion(groupName,type,version,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema identified by version from the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class) })
+ public Response deleteSchemaVersionOrinal(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Version ordinal",required=true) @PathParam("versionOrdinal") Integer versionOrdinal
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteSchemaVersionOrinal(groupName,versionOrdinal,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/codecTypes")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class) })
+ public Response getCodecTypesList(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getCodecTypesList(groupName,securityContext);
+ }
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class) })
+ public Response getEncodingId(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Get schema corresponding to the version" ,required=true) GetEncodingIdRequest getEncodingIdRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getEncodingId(groupName,getEncodingIdRequest,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class) })
+ public Response getEncodingInfo(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Encoding id that identifies a unique combination of schema and codec type",required=true) @PathParam("encodingId") Integer encodingId
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getEncodingInfo(groupName,encodingId,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/history")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class) })
+ public Response getGroupHistory(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getGroupHistory(groupName,securityContext);
+ }
+ @GET
+ @Path("/{groupName}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class) })
+ public Response getGroupProperties(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getGroupProperties(groupName,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class) })
+ public Response getSchemaFromVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type",required=true) @PathParam("type") String type
+,@ApiParam(value = "Version number",required=true) @PathParam("version") Integer version
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaFromVersion(groupName,type,version,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class) })
+ public Response getSchemaFromVersionOrdinal(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Version ordinal",required=true) @PathParam("versionOrdinal") Integer versionOrdinal
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaFromVersionOrdinal(groupName,versionOrdinal,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered. It does not automatically register the schema. To add new schema use addSchema", response = VersionInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error fetching version for schema", response = Void.class) })
+ public Response getSchemaVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Get schema corresponding to the version" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaVersion(groupName,schemaInfo,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/versions")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group", response = SchemaVersionsList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group schema versions", response = Void.class) })
+ public Response getSchemaVersions(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Type of object the schema describes.") @QueryParam("type") String type
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaVersions(groupName,type,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group's latest schemas", response = Void.class) })
+ public Response getSchemas(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Type of object") @QueryParam("type") String type
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemas(groupName,type,securityContext);
+ }
+ @GET
+
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class) })
+ public Response listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken
+,@ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.listGroups(continuationToken,limit,securityContext);
+ }
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class) })
+ public Response updateSchemaValidationRules(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "update group policy" ,required=true) UpdateValidationRulesRequest updateValidationRulesRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.updateSchemaValidationRules(groupName,updateValidationRulesRequest,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class) })
+ public Response validate(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Checks if schema is valid with respect to supplied validation rules" ,required=true) ValidateRequest validateRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.validate(groupName,validateRequest,securityContext);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
new file mode 100644
index 000000000..dd8d9ef40
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
@@ -0,0 +1,54 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public abstract class GroupsApiService {
+ public abstract Response addCodecType(String groupName,String codecType,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response addSchema(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response canRead(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response createGroup(CreateGroupRequest createGroupRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteGroup(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteSchemaVersion(String groupName,String type,Integer version,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteSchemaVersionOrinal(String groupName,Integer versionOrdinal,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getCodecTypesList(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getEncodingId(String groupName,GetEncodingIdRequest getEncodingIdRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getEncodingInfo(String groupName,Integer encodingId,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getGroupHistory(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getGroupProperties(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaFromVersion(String groupName,String type,Integer version,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaFromVersionOrdinal(String groupName,Integer versionOrdinal,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaVersion(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaVersions(String groupName, String type,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemas(String groupName, String type,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response listGroups( String continuationToken, Integer limit,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response updateSchemaValidationRules(String groupName,UpdateValidationRulesRequest updateValidationRulesRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response validate(String groupName,ValidateRequest validateRequest,SecurityContext securityContext) throws NotFoundException;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
new file mode 100644
index 000000000..e6179d25f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
@@ -0,0 +1,18 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.util.Json;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.Provider;
+import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+
+@Provider
+@Produces({MediaType.APPLICATION_JSON})
+public class JacksonJsonProvider extends JacksonJaxbJsonProvider {
+ private static ObjectMapper commonMapper = Json.mapper();
+
+ public JacksonJsonProvider() {
+ super.setMapper(commonMapper);
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
new file mode 100644
index 000000000..e9d99721b
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
@@ -0,0 +1,10 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class NotFoundException extends ApiException {
+ private int code;
+ public NotFoundException (int code, String msg) {
+ super(code, msg);
+ this.code = code;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
new file mode 100644
index 000000000..295bd1d86
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
@@ -0,0 +1,74 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.SchemasApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.factories.SchemasApiServiceFactory;
+
+import io.swagger.annotations.ApiParam;
+import io.swagger.jaxrs.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.Map;
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.servlet.ServletConfig;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.*;
+import javax.validation.constraints.*;
+
+@Path("/schemas")
+
+
+@io.swagger.annotations.Api(description = "the schemas API")
+
+public class SchemasApi {
+ private final SchemasApiService delegate;
+
+ public SchemasApi(@Context ServletConfig servletContext) {
+ SchemasApiService delegate = null;
+
+ if (servletContext != null) {
+ String implClass = servletContext.getInitParameter("SchemasApi.implementation");
+ if (implClass != null && !"".equals(implClass.trim())) {
+ try {
+ delegate = (SchemasApiService) Class.forName(implClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ if (delegate == null) {
+ delegate = SchemasApiServiceFactory.getSchemasApi();
+ }
+
+ this.delegate = delegate;
+ }
+
+ @POST
+ @Path("/addedTo")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags={ "Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class) })
+ public Response getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaReferences(schemaInfo,securityContext);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
new file mode 100644
index 000000000..bcc19dd03
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
@@ -0,0 +1,22 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public abstract class SchemasApiService {
+ public abstract Response getSchemaReferences(SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
new file mode 100644
index 000000000..5d19e5e5f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
@@ -0,0 +1,42 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class StringUtil {
+ /**
+ * Check if the given array contains the given value (with case-insensitive comparison).
+ *
+ * @param array The array
+ * @param value The value to search
+ * @return true if the array contains the value
+ */
+ public static boolean containsIgnoreCase(String[] array, String value) {
+ for (String str : array) {
+ if (value == null && str == null) return true;
+ if (value != null && value.equalsIgnoreCase(str)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Join an array of strings with the given separator.
+ *
+ * Note: This might be replaced by utility method from commons-lang or guava someday
+ * if one of those libraries is added as dependency.
+ *
+ *
+ * @param array The array of strings
+ * @param separator The separator
+ * @return the resulting string
+ */
+ public static String join(String[] array, String separator) {
+ int len = array.length;
+ if (len == 0) return "";
+
+ StringBuilder out = new StringBuilder();
+ out.append(array[0]);
+ for (int i = 1; i < len; i++) {
+ out.append(separator).append(array[i]);
+ }
+ return out.toString();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
new file mode 100644
index 000000000..3145181ad
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
@@ -0,0 +1,13 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.factories;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.GroupsApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.impl.GroupsApiServiceImpl;
+
+
+public class GroupsApiServiceFactory {
+ private final static GroupsApiService service = new GroupsApiServiceImpl();
+
+ public static GroupsApiService getGroupsApi() {
+ return service;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
new file mode 100644
index 000000000..8587b6fef
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
@@ -0,0 +1,13 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.factories;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.SchemasApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.impl.SchemasApiServiceImpl;
+
+
+public class SchemasApiServiceFactory {
+ private final static SchemasApiService service = new SchemasApiServiceImpl();
+
+ public static SchemasApiService getSchemasApi() {
+ return service;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
new file mode 100644
index 000000000..97aea99a9
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
@@ -0,0 +1,134 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.impl;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public class GroupsApiServiceImpl extends GroupsApiService {
+ @Override
+ public Response addCodecType(String groupName, String codecType, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response addSchema(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response canRead(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response createGroup(CreateGroupRequest createGroupRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteGroup(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteSchemaVersion(String groupName, String type, Integer version, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteSchemaVersionOrinal(String groupName, Integer versionOrdinal, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getCodecTypesList(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getEncodingId(String groupName, GetEncodingIdRequest getEncodingIdRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getEncodingInfo(String groupName, Integer encodingId, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getGroupHistory(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getGroupProperties(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaFromVersion(String groupName, String type, Integer version, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaFromVersionOrdinal(String groupName, Integer versionOrdinal, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaVersion(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaVersions(String groupName, String type, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemas(String groupName, String type, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response listGroups( String continuationToken, Integer limit, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response updateSchemaValidationRules(String groupName, UpdateValidationRulesRequest updateValidationRulesRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response validate(String groupName, ValidateRequest validateRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
new file mode 100644
index 000000000..565f0f2fb
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
@@ -0,0 +1,26 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.impl;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public class SchemasApiServiceImpl extends SchemasApiService {
+ @Override
+ public Response getSchemaReferences(SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java b/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
new file mode 100644
index 000000000..fa261ab42
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
@@ -0,0 +1,243 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.transform;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.generated.rest.model.Compatibility;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRule;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import org.apache.commons.lang3.NotImplementedException;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Provides translation (encode/decode) between the Model classes and its REST representation.
+ */
+public class ModelHelper {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ // region decode
+ public static io.pravega.schemaregistry.contract.data.SchemaInfo decode(SchemaInfo schemaInfo) {
+ Preconditions.checkArgument(schemaInfo != null);
+ Preconditions.checkArgument(schemaInfo.getType() != null);
+ Preconditions.checkArgument(schemaInfo.getSerializationFormat() != null);
+ Preconditions.checkArgument(schemaInfo.getProperties() != null);
+ Preconditions.checkArgument(schemaInfo.getSchemaData() != null);
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = decode(schemaInfo.getSerializationFormat());
+ return new io.pravega.schemaregistry.contract.data.SchemaInfo(schemaInfo.getType(),
+ serializationFormat, ByteBuffer.wrap(schemaInfo.getSchemaData()), ImmutableMap.copyOf(schemaInfo.getProperties()));
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SerializationFormat decode(SerializationFormat serializationFormat) {
+ Preconditions.checkArgument(serializationFormat != null);
+ switch (serializationFormat.getSerializationFormat()) {
+ case CUSTOM:
+ Preconditions.checkArgument(serializationFormat.getCustomTypeName() != null);
+ return io.pravega.schemaregistry.contract.data.SerializationFormat.custom(serializationFormat.getCustomTypeName());
+ default:
+ return searchEnum(io.pravega.schemaregistry.contract.data.SerializationFormat.class, serializationFormat.getSerializationFormat().name());
+ }
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SchemaValidationRules decode(SchemaValidationRules rules) {
+ Preconditions.checkArgument(rules != null);
+ Preconditions.checkArgument(rules.getRules() != null);
+ List list = rules.getRules().entrySet().stream().map(rule -> {
+ if (rule.getValue().getRule() instanceof Map) {
+ String name = (String) ((Map) rule.getValue().getRule()).get("name");
+ Preconditions.checkArgument(name.equals(Compatibility.class.getSimpleName()));
+
+ return decode(MAPPER.convertValue(rule.getValue().getRule(), Compatibility.class));
+ } else if (rule.getValue().getRule() instanceof Compatibility) {
+ return decode((Compatibility) rule.getValue().getRule());
+ } else {
+ throw new IllegalArgumentException("Rule not supported");
+ }
+ }).collect(Collectors.toList());
+ return io.pravega.schemaregistry.contract.data.SchemaValidationRules.of(list);
+ }
+
+ public static io.pravega.schemaregistry.contract.data.Compatibility decode(Compatibility compatibility) {
+ Preconditions.checkArgument(compatibility.getName() != null);
+ Preconditions.checkArgument(compatibility.getPolicy() != null);
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.BACKWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getBackwardTill() != null);
+ }
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.FORWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getForwardTill() != null);
+ }
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getBackwardTill() != null);
+ Preconditions.checkArgument(compatibility.getForwardTill() != null);
+ }
+
+ io.pravega.schemaregistry.contract.data.VersionInfo backwardTill = compatibility.getBackwardTill() == null ? null : decode(compatibility.getBackwardTill());
+ io.pravega.schemaregistry.contract.data.VersionInfo forwardTill = compatibility.getForwardTill() == null ? null : decode(compatibility.getForwardTill());
+
+ return new io.pravega.schemaregistry.contract.data.Compatibility(
+ searchEnum(io.pravega.schemaregistry.contract.data.Compatibility.Type.class, compatibility.getPolicy().name()),
+ backwardTill, forwardTill);
+ }
+
+ public static io.pravega.schemaregistry.contract.data.VersionInfo decode(VersionInfo versionInfo) {
+ Preconditions.checkArgument(versionInfo != null);
+ Preconditions.checkArgument(versionInfo.getType() != null);
+ Preconditions.checkArgument(versionInfo.getVersion() != null);
+ Preconditions.checkArgument(versionInfo.getOrdinal() != null);
+ return new io.pravega.schemaregistry.contract.data.VersionInfo(versionInfo.getType(), versionInfo.getVersion(), versionInfo.getOrdinal());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.EncodingInfo decode(EncodingInfo encodingInfo) {
+ Preconditions.checkArgument(encodingInfo != null);
+ return new io.pravega.schemaregistry.contract.data.EncodingInfo(decode(encodingInfo.getVersionInfo()),
+ decode(encodingInfo.getSchemaInfo()), encodingInfo.getCodecType());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SchemaWithVersion decode(SchemaWithVersion schemaWithVersion) {
+ Preconditions.checkArgument(schemaWithVersion != null);
+ return new io.pravega.schemaregistry.contract.data.SchemaWithVersion(decode(schemaWithVersion.getSchemaInfo()),
+ decode(schemaWithVersion.getVersion()));
+ }
+
+ public static io.pravega.schemaregistry.contract.data.GroupHistoryRecord decode(GroupHistoryRecord schemaEvolution) {
+ Preconditions.checkArgument(schemaEvolution != null);
+
+ return new io.pravega.schemaregistry.contract.data.GroupHistoryRecord(decode(schemaEvolution.getSchemaInfo()),
+ decode(schemaEvolution.getVersion()), decode(schemaEvolution.getValidationRules()), schemaEvolution.getTimestamp(),
+ schemaEvolution.getSchemaString());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.EncodingId decode(EncodingId encodingId) {
+ Preconditions.checkArgument(encodingId != null);
+ Preconditions.checkArgument(encodingId.getEncodingId() != null);
+
+ return new io.pravega.schemaregistry.contract.data.EncodingId(encodingId.getEncodingId());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.GroupProperties decode(GroupProperties groupProperties) {
+ Preconditions.checkArgument(groupProperties != null);
+ Preconditions.checkArgument(groupProperties.isAllowMultipleTypes() != null);
+
+ return io.pravega.schemaregistry.contract.data.GroupProperties.builder().serializationFormat(decode(groupProperties.getSerializationFormat()))
+ .schemaValidationRules(decode(groupProperties.getSchemaValidationRules())).allowMultipleTypes(groupProperties.isAllowMultipleTypes())
+ .properties(ImmutableMap.copyOf(groupProperties.getProperties())).build();
+ }
+ // endregion
+
+ // region encode
+ public static GroupHistoryRecord encode(io.pravega.schemaregistry.contract.data.GroupHistoryRecord groupHistoryRecord) {
+ return new GroupHistoryRecord().schemaInfo(encode(groupHistoryRecord.getSchema()))
+ .version(encode(groupHistoryRecord.getVersion()))
+ .validationRules(encode(groupHistoryRecord.getRules()))
+ .timestamp(groupHistoryRecord.getTimestamp())
+ .schemaString(groupHistoryRecord.getSchemaString());
+ }
+
+ public static SchemaValidationRules encode(io.pravega.schemaregistry.contract.data.SchemaValidationRules rules) {
+ Map map = rules.getRules().entrySet().stream().collect(Collectors.toMap(rule -> {
+ if (rule.getValue() instanceof io.pravega.schemaregistry.contract.data.Compatibility) {
+ return io.pravega.schemaregistry.contract.generated.rest.model.Compatibility.class.getSimpleName();
+ } else {
+ throw new NotImplementedException("Rule not implemented");
+ }
+ }, rule -> {
+ SchemaValidationRule schemaValidationRule;
+ if (rule.getValue() instanceof io.pravega.schemaregistry.contract.data.Compatibility) {
+ schemaValidationRule = new SchemaValidationRule().rule(encode((io.pravega.schemaregistry.contract.data.Compatibility) rule.getValue()));
+ } else {
+ throw new NotImplementedException("Rule not implemented");
+ }
+ return schemaValidationRule;
+ }));
+ return new SchemaValidationRules().rules(map);
+ }
+
+ public static Compatibility encode(io.pravega.schemaregistry.contract.data.Compatibility compatibility) {
+ Compatibility policy = new io.pravega.schemaregistry.contract.generated.rest.model.Compatibility()
+ .name(compatibility.getName())
+ .policy(searchEnum(Compatibility.PolicyEnum.class, compatibility.getCompatibility().name()));
+ if (compatibility.getBackwardTill() != null) {
+ VersionInfo backwardTill = encode(compatibility.getBackwardTill());
+ policy = policy.backwardTill(backwardTill);
+ }
+ if (compatibility.getForwardTill() != null) {
+ VersionInfo forwardTill = encode(compatibility.getForwardTill());
+ policy = policy.forwardTill(forwardTill);
+ }
+ return policy;
+ }
+
+ public static SchemaWithVersion encode(io.pravega.schemaregistry.contract.data.SchemaWithVersion schemaWithVersion) {
+ return new SchemaWithVersion().schemaInfo(encode(schemaWithVersion.getSchemaInfo()))
+ .version(encode(schemaWithVersion.getVersionInfo()));
+ }
+
+ public static GroupProperties encode(io.pravega.schemaregistry.contract.data.GroupProperties groupProperties) {
+ return new GroupProperties()
+ .serializationFormat(encode(groupProperties.getSerializationFormat()))
+ .properties(groupProperties.getProperties())
+ .allowMultipleTypes(groupProperties.isAllowMultipleTypes())
+ .schemaValidationRules(encode(groupProperties.getSchemaValidationRules()));
+ }
+
+ public static VersionInfo encode(io.pravega.schemaregistry.contract.data.VersionInfo versionInfo) {
+ return new VersionInfo().type(versionInfo.getType()).version(versionInfo.getVersion()).ordinal(versionInfo.getOrdinal());
+ }
+
+ public static SchemaInfo encode(io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo) {
+ return new SchemaInfo().properties(schemaInfo.getProperties()).schemaData(schemaInfo.getSchemaData().array())
+ .type(schemaInfo.getType()).serializationFormat(encode(schemaInfo.getSerializationFormat()));
+ }
+
+ public static SerializationFormat encode(io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat) {
+ if (serializationFormat.equals(io.pravega.schemaregistry.contract.data.SerializationFormat.Custom)) {
+ Preconditions.checkArgument(serializationFormat.getCustomTypeName() != null);
+ SerializationFormat serializationFormatModel = new SerializationFormat().serializationFormat(SerializationFormat.SerializationFormatEnum.CUSTOM);
+ return serializationFormatModel.customTypeName(serializationFormat.getCustomTypeName());
+ } else {
+ return new SerializationFormat().serializationFormat(
+ searchEnum(SerializationFormat.SerializationFormatEnum.class, serializationFormat.name()));
+ }
+ }
+
+ public static EncodingId encode(io.pravega.schemaregistry.contract.data.EncodingId encodingId) {
+ return new EncodingId().encodingId(encodingId.getId());
+ }
+
+ public static EncodingInfo encode(io.pravega.schemaregistry.contract.data.EncodingInfo encodingInfo) {
+ return new EncodingInfo().codecType(encodingInfo.getCodecType())
+ .versionInfo(encode(encodingInfo.getVersionInfo()))
+ .schemaInfo(encode(encodingInfo.getSchemaInfo()));
+ }
+
+ // endregion
+
+ private static > T searchEnum(Class enumeration, String search) {
+ for (T each : enumeration.getEnumConstants()) {
+ if (each.name().compareToIgnoreCase(search) == 0) {
+ return each;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java b/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
new file mode 100644
index 000000000..7ce526198
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
@@ -0,0 +1,554 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.v1;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+import io.swagger.annotations.ApiParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Response;
+
+public class ApiV1 {
+ @Path("/ping")
+ public interface Ping {
+ @GET
+ Response ping();
+ }
+
+ /**
+ * Sync Group apis. Identical to {@link GroupsApiAsync}. All methods in this interface are synchronous and return {@link Response} object.
+ * The purposes of this interface is to be used by proxy-client.
+ */
+ @Path("/v1/groups")
+ @io.swagger.annotations.Api(description = "the groups API")
+ public interface GroupsApi {
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response addCodecType(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "The codec type", required = true) String codecType);
+
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response addSchema(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add new schema to group", required = true) SchemaInfo schemaInfo);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class)})
+ Response canRead(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules.", required = true) SchemaInfo schemaInfo);
+
+ @POST
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response createGroup(@ApiParam(value = "The Group configuration", required = true) CreateGroupRequest createGroupRequest);
+
+ @DELETE
+ @Path("/{groupName}")
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class)})
+ Response deleteGroup(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/codecTypes")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class)})
+ Response getCodecTypesList(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class)})
+ Response getEncodingInfo(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Encoding id that identifies a unique combination of schema and codecType", required = true) @PathParam("encodingId") Integer encodingId);
+
+ @GET
+ @Path("/{groupName}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getGroupProperties(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/history")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class)})
+ Response getGroupHistory(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/schemas/versions")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemaVersions(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type") @QueryParam("type") String type);
+
+ @GET
+ @Path("/{groupName}/schemas")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemas(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type of object") @QueryParam("type") String type);
+
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class)})
+ Response getEncodingId(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) GetEncodingIdRequest getEncodingIdRequest);
+
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version deleted", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ Response deleteSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version);
+
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ Response getSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version);
+
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ public Response getSchemaFromVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version);
+
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ Response deleteSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered.", response = VersionInfo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) SchemaInfo schemaInfo);
+
+ @GET
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class)})
+ Response listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken,
+ @ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit);
+
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class)})
+ Response updateSchemaValidationRules(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "update group policy", required = true) UpdateValidationRulesRequest updateValidationRulesRequest);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class)})
+ Response validate(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema is valid with respect to supplied validation rules", required = true) ValidateRequest validateRequest);
+ }
+
+ /**
+ * ASync Group apis. Identical to {@link GroupsApi}. All methods in this interface are asynchronous and use
+ * {@link AsyncResponse}. This is used on service side so that all api implementation is asynchronous.
+ */
+ @Path("/v1/groups")
+ @io.swagger.annotations.Api(description = "the groups API")
+ public interface GroupsApiAsync {
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while registering codectype to a Group", response = Void.class)})
+ void addCodecType(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add codec type", required = true) String codecType, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while adding a schema", response = Void.class)})
+ void addSchema(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add new schema to group", required = true) SchemaInfo schemaInfo, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class)})
+ void canRead(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules.", required = true) SchemaInfo schemaInfo, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ void createGroup(@ApiParam(value = "The Group configuration", required = true) CreateGroupRequest createGroupRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @DELETE
+ @Path("/{groupName}")
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class)})
+ void deleteGroup(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/codecTypes")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class)})
+ void getCodecTypesList(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class)})
+ void getEncodingInfo(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Encoding id that identifies a unique combination of schema and codecType", required = true) @PathParam("encodingId") Integer encodingId, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getGroupProperties(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/history")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class)})
+ void getGroupHistory(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/versions")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group.", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getSchemaVersions(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type") @QueryParam("type") String type,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group's latest schemas", response = Void.class)})
+ void getSchemas(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type of object") @QueryParam("type") String type,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class)})
+ void getEncodingId(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) GetEncodingIdRequest getEncodingIdRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ void getSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ void deleteSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ void getSchemaFromVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version,
+ @Suspended AsyncResponse asyncResponse);
+
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ void deleteSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version,
+ @Suspended AsyncResponse asyncResponse);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered.", response = VersionInfo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) SchemaInfo schemaInfo,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class)})
+ void listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken,
+ @ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class)})
+ void updateSchemaValidationRules(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "update group policy", required = true) UpdateValidationRulesRequest updateValidationRulesRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class)})
+ void validate(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema is valid with respect to supplied validation rules", required = true) ValidateRequest validateRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+ }
+
+
+ /**
+ * Sync Schemas apis. Identical to {@link SchemasApiAsync}. All methods in this interface are synchronous and return {@link Response} object.
+ * The purposes of this interface is to be used by proxy-client.
+ */
+ @Path("/v1/schemas")
+ @io.swagger.annotations.Api(description = "the schemas API")
+ public interface SchemasApi {
+ @POST
+ @Path("/addedTo")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class)})
+ Response getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema", required = true) SchemaInfo schemaInfo);
+
+ }
+
+ /**
+ * Sync Schemas apis. Identical to {@link SchemasApi}. All methods in this interface are asynchronous.
+ */
+ @Path("/v1/schemas")
+ @io.swagger.annotations.Api(description = "the schemas API")
+ public interface SchemasApiAsync {
+ @POST
+ @Path("/addedTo")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class)})
+ void getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema", required = true) SchemaInfo schemaInfo,
+ @Suspended AsyncResponse asyncResponse);
+ }
+
+}
diff --git a/contract/src/main/swagger/README.md b/contract/src/main/swagger/README.md
new file mode 100644
index 000000000..bc196acf3
--- /dev/null
+++ b/contract/src/main/swagger/README.md
@@ -0,0 +1,44 @@
+
+Instructions to generate Server REST API stubs
+
+## Delete previously generated directory
+```
+rm -Rf server/src/main/java/io/pravega/schemaregistry/server/io.pravega.rest/generated
+```
+
+## Update schemaregistry.yaml
+All REST API modifications should be done by updating the swagger/schemaregistry.yaml specification file.
+This can be done manually or by using the online editor at http://editor.swagger.io.
+
+## Download Swagger codegen
+Download swagger-codegen-cli from maven - http://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.2.3/swagger-codegen-cli-2.2.3.jar
+
+## Generate the API stubs using Swagger Codegen
+```
+java -jar swagger-codegen-cli.jar generate -i /contract/src/main/swagger/SchemaRegistry.yaml -l jaxrs -c /contract/src/main/swagger/server.config.json -o /contract/
+```
+
+## Remove extra files created by codegen
+All files that get generated outside of the contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest folder should be deleted and not committed to git.
+
+## Update ApiV1.java
+The JAXRS API stubs decorated with swagger annotations are generated in .../contract/io/pravega/schemaregistry/contract/v1/ApiV1.java class.
+Copy these API descriptions into interfaces in .../contract/io.pravega.schemaregistry/contract//v1/ApiV1.java.
+Also make an asynchronour version of APIs in .../contract/io.pravega.schemaregistry/server/rest/v1/ApiV1.java to use only jersey async interfaces.
+
+## Generate documentation
+### Download Swagger2Markup CLI
+https://jcenter.bintray.com/io/github/swagger2markup/swagger2markup-cli/1.3.3/swagger2markup-cli-1.3.3.jar
+
+### Generate and save the markup documentation
+```
+java -Dswagger2markup.markupLanguage=MARKDOWN -Dswagger2markup.generatedExamplesEnabled=true -jar swagger2markup-cli-1.3.3.jar convert -i /contract/src/main/swagger/schemaregistry.yaml -f /documentation/src/docs/io.pravega.rest/restapis
+```
diff --git a/contract/src/main/swagger/SchemaRegistry.yaml b/contract/src/main/swagger/SchemaRegistry.yaml
new file mode 100644
index 000000000..92dba5fd1
--- /dev/null
+++ b/contract/src/main/swagger/SchemaRegistry.yaml
@@ -0,0 +1,867 @@
+#
+# Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Description of the Pravega Schema Registry APIs.
+
+swagger: "2.0"
+info:
+ description: "REST APIs for Pravega Schema Registry."
+ version: "0.0.1"
+ title: Pravega Schema Registry APIs
+ license:
+ name: "Apache 2.0"
+ url: "http://www.apache.org/licenses/LICENSE-2.0"
+basePath: "/v1"
+tags:
+- name: "Group"
+ description: "Group related APIs"
+- name: "Schemas"
+ description: "Schema related APIs"
+schemes:
+ - http
+paths:
+ /groups:
+ get:
+ tags:
+ - "Group"
+ operationId: listGroups
+ description: List all groups
+ produces:
+ - application/json
+ parameters:
+ - in: query
+ name: continuationToken
+ type: string
+ description: Continuation token
+ - in: query
+ name: limit
+ type: integer
+ description: The numbers of items to return
+ required:
+ - limit
+ responses:
+ 200:
+ description: List of all groups
+ schema:
+ $ref: "#/definitions/ListGroupsResponse"
+ 500:
+ description: Internal server error while fetching the list of Groups
+ post:
+ tags:
+ - "Group"
+ operationId: createGroup
+ description: Create a new Group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: CreateGroupRequest
+ description: The Group configuration
+ required: true
+ schema:
+ type: object
+ properties:
+ groupName:
+ type: string
+ groupProperties:
+ $ref: "#/definitions/GroupProperties"
+ required:
+ - groupName
+ - groupProperties
+ responses:
+ 201:
+ description: Successfully added group
+ 409:
+ description: Group with given name already exists
+ 500:
+ description: Internal server error while creating a Group
+ /groups/{groupName}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getGroupProperties
+ description: Fetch the properties of an existing Group
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Group properties
+ schema:
+ $ref: "#/definitions/GroupProperties"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group details
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteGroup
+ description: Delete a Group
+ responses:
+ 204:
+ description: Successfully deleted the Group
+ 500:
+ description: Internal server error while deleting the Group
+ /groups/{groupName}/history:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getGroupHistory
+ description: Fetch the history of schema evolution of a Group
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Group history
+ schema:
+ $ref: "#/definitions/GroupHistory"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group history
+ /groups/{groupName}/rules:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ put:
+ tags:
+ - "Group"
+ operationId: updateSchemaValidationRules
+ description: update schema validation rules of an existing Group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: UpdateValidationRulesRequest
+ description: update group policy
+ required: true
+ schema:
+ type: object
+ properties:
+ validationRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ previousRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ nullable: true
+ required:
+ - validationRules
+ responses:
+ 200:
+ description: Updated schema validation policy
+ 404:
+ description: Group with given name not found
+ 409:
+ description: Write conflict
+ 500:
+ description: Internal server error while updating Group's schema validation rules
+ /groups/{groupName}/schemas:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: query
+ name: type
+ type: string
+ description: Type of object
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemas
+ description: Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Latest schemas for all objects identified by SchemaInfo#type under the group
+ schema:
+ $ref: "#/definitions/SchemaVersionsList"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group's latest schemas
+ /groups/{groupName}/schemas/versions:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaVersions
+ description: Get all schema versions for the group
+ parameters:
+ - in: query
+ name: type
+ type: string
+ description: Type of object the schema describes.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Versioned history of schemas registered under the group
+ schema:
+ $ref: "#/definitions/SchemaVersionsList"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group schema versions
+ post:
+ tags:
+ - "Group"
+ operationId: addSchema
+ description: Adds a new schema to the group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Add new schema to group
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 201:
+ description: Successfully added schema to the group
+ schema:
+ $ref: "#/definitions/VersionInfo"
+ 404:
+ description: Group not found
+ 409:
+ description: Incompatible schema
+ 417:
+ description: Invalid serialization format
+ 500:
+ description: Internal server error while adding schema to group
+ /groups/{groupName}/schemas/versions/find:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: getSchemaVersion
+ description: Get the version for the schema if it is registered. It does not automatically register the schema. To add new schema use addSchema
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Get schema corresponding to the version
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema version
+ schema:
+ $ref: "#/definitions/VersionInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error fetching version for schema
+ /groups/{groupName}/schemas/versions/{versionOrdinal}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: versionOrdinal
+ description: Version ordinal
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaFromVersionOrdinal
+ description: Get schema from the version ordinal that uniquely identifies the schema in the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema corresponding to the version
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching schema from version
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteSchemaVersionOrinal
+ description: Delete schema identified by version from the group.
+ produces:
+ - application/json
+ responses:
+ 204:
+ description: Schema corresponding to the version
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while deleting schema from group
+ /groups/{groupName}/schemas/{type}/versions/{version}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: type
+ description: Schema type from SchemaInfo#type or VersionInfo#type
+ required: true
+ type: string
+ - in: path
+ name: version
+ description: Version number
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaFromVersion
+ description: Get schema from the version ordinal that uniquely identifies the schema in the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema corresponding to the version
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching schema from version
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteSchemaVersion
+ description: Delete schema version from the group.
+ produces:
+ - application/json
+ responses:
+ 204:
+ description: Schema corresponding to the version
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while deleting schema from group
+ /groups/{groupName}/schemas/versions/validate:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: validate
+ description: Checks if given schema is compatible with schemas in the registry for current policy setting.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: ValidateRequest
+ description: Checks if schema is valid with respect to supplied validation rules
+ required: true
+ schema:
+ type: object
+ properties:
+ schemaInfo:
+ $ref: "#/definitions/SchemaInfo"
+ validationRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ required:
+ - schemaInfo
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema validation response
+ schema:
+ $ref: "#/definitions/Valid"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while trying to validate schema
+ /groups/{groupName}/schemas/versions/canRead:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: canRead
+ description: Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Checks if schema can be used to read the data in the stream based on compatibility rules.
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Response to tell whether schema can be used to read existing schemas
+ schema:
+ $ref: "#/definitions/CanRead"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while checking schema for readability
+ /groups/{groupName}/encodings:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ put:
+ tags:
+ - "Group"
+ operationId: getEncodingId
+ description: Get an encoding id that uniquely identifies a schema version and codec type pair.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: GetEncodingIdRequest
+ description: Get schema corresponding to the version
+ required: true
+ schema:
+ type: object
+ properties:
+ versionInfo:
+ $ref: "#/definitions/VersionInfo"
+ codecType:
+ type: string
+ required:
+ - versionInfo
+ - codecType
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Encoding
+ schema:
+ $ref: "#/definitions/EncodingId"
+ 404:
+ description: Group with given name or version not found
+ 412:
+ description: Codec type not registered
+ 500:
+ description: Internal server error while getting encoding id
+ /groups/{groupName}/encodings/{encodingId}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: encodingId
+ description: Encoding id that identifies a unique combination of schema and codec type
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getEncodingInfo
+ description: Get the encoding information corresponding to the encoding id.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Encoding
+ schema:
+ $ref: "#/definitions/EncodingInfo"
+ 404:
+ description: Group or encoding id with given name not found
+ 500:
+ description: Internal server error while getting encoding info corresponding to encoding id
+ /groups/{groupName}/codecTypes:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getCodecTypesList
+ description: Get codecTypes for the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found CodecTypes
+ schema:
+ $ref: "#/definitions/CodecTypesList"
+ 404:
+ description: Group or encoding id with given name not found
+ 500:
+ description: Internal server error while fetching codecTypes registered
+ post:
+ tags:
+ - "Group"
+ operationId: addCodecType
+ description: Adds a new codecType to the group.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: codecType
+ description: The codecType
+ required: true
+ schema:
+ type: string
+ responses:
+ 201:
+ description: Successfully added codecType to group
+ 404:
+ description: Group not found
+ 500:
+ description: Internal server error while registering codectype to a Group
+ /schemas/addedTo:
+ parameters:
+ post:
+ tags:
+ - "Schema"
+ operationId: getSchemaReferences
+ description: Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Get schema references for the supplied schema
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema version
+ schema:
+ $ref: "#/definitions/AddedTo"
+ 404:
+ description: Schema not found
+ 500:
+ description: Internal server error while fetching Schema references
+definitions:
+ ListGroupsResponse:
+ type: object
+ description: Map of Group names to group properties. For partially created groups, the group properties may be null.
+ properties:
+ groups:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/GroupProperties"
+ continuationToken:
+ description: Continuation token to identify the position of last group in the response.
+ type: string
+ required:
+ - continuationToken
+ GroupProperties:
+ type: object
+ description: Metadata for a group.
+ properties:
+ serializationFormat:
+ description: serialization format for the group.
+ $ref: "#/definitions/SerializationFormat"
+ schemaValidationRules:
+ description: Validation rules to apply while registering new schema.
+ $ref: "#/definitions/SchemaValidationRules"
+ allowMultipleTypes:
+ description: Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.
+ type: boolean
+ properties:
+ description: User defined Key value strings.
+ type: object
+ additionalProperties:
+ type: string
+ minLength: 0
+ maxLength: 40
+ required:
+ - serializationFormat
+ - allowMultipleTypes
+ - schemaValidationRules
+ SerializationFormat:
+ type: object
+ description: Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.
+ properties:
+ serializationFormat:
+ type: string
+ enum:
+ - Avro
+ - Protobuf
+ - Json
+ - Any
+ - Custom
+ customTypeName:
+ type: string
+ required:
+ - serializationFormat
+ SchemaInfo:
+ type: object
+ description: Schema information object that encapsulates various properties of a schema.
+ properties:
+ type:
+ description: Name of the schema. This identifies the type of object the schema payload represents.
+ type: string
+ serializationFormat:
+ description: Type of schema.
+ $ref: "#/definitions/SerializationFormat"
+ schemaData:
+ description: Base64 encoded string for binary data for schema.
+ type: string
+ format: binary
+ properties:
+ description: User defined key value strings.
+ type: object
+ additionalProperties:
+ type: string
+ minLength: 0
+ maxLength: 40
+ required:
+ - type
+ - serializationFormat
+ - schemaData
+ VersionInfo:
+ description: Version information object.
+ type: object
+ properties:
+ type:
+ description: Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.
+ type: string
+ version:
+ description: Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.
+ type: integer
+ format: int32
+ ordinal:
+ description: Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.
+ type: integer
+ format: int32
+ required:
+ - type
+ - version
+ - ordinal
+ SchemaWithVersion:
+ type: object
+ description: Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.
+ properties:
+ schemaInfo:
+ description: Schema information.
+ $ref: "#/definitions/SchemaInfo"
+ version:
+ description: Version information.
+ $ref: "#/definitions/VersionInfo"
+ required:
+ - schemaInfo
+ - version
+ SchemaVersionsList:
+ type: object
+ description: List of schemas with their versions.
+ properties:
+ schemas:
+ description: List of schemas with their versions.
+ type: array
+ items:
+ $ref: "#/definitions/SchemaWithVersion"
+ EncodingId:
+ type: object
+ description: Encoding id that uniquely identifies a schema version and codec type pair.
+ properties:
+ encodingId:
+ type: integer
+ format: int32
+ description: encoding id generated by service.
+ required:
+ - encodingId
+ EncodingInfo:
+ type: object
+ description: Encoding information object that resolves the schema version and codec type used for corresponding encoding id.
+ properties:
+ schemaInfo:
+ description: Schema information object.
+ $ref: "#/definitions/SchemaInfo"
+ versionInfo:
+ description: Version information object.
+ $ref: "#/definitions/VersionInfo"
+ codecType:
+ description: Codec type.
+ type: string
+ required:
+ - schemaInfo
+ - versionInfo
+ - codecType
+ Compatibility:
+ type: object
+ description: Schema Compatibility validation rule.
+ required:
+ - name
+ - policy
+ properties:
+ name:
+ type: string
+ description: Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be "Compatibility".
+ policy:
+ description: Compatibility policy enum.
+ type: string
+ enum:
+ - AllowAny
+ - DenyAll
+ - Backward
+ - Forward
+ - ForwardTransitive
+ - BackwardTransitive
+ - BackwardTill
+ - ForwardTill
+ - BackwardAndForwardTill
+ - Full
+ - FullTransitive
+ backwardTill:
+ description: Version for backward till if policy is BackwardTill or BackwardAndForwardTill.
+ $ref: "#/definitions/VersionInfo"
+ forwardTill:
+ description: Version for forward till if policy is ForwardTill or BackwardAndForwardTill.
+ $ref: "#/definitions/VersionInfo"
+ SchemaValidationRules:
+ type: object
+ description: Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.
+ properties:
+ rules:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/SchemaValidationRule"
+ SchemaValidationRule:
+ type: object
+ description: Schema validation rule base class.
+ required:
+ - rule
+ properties:
+ rule:
+ description: Specific schema validation rule. The only rule we have presently is Compatibility. The "name" is used to identify specific Rule type. The only rule supported in this is Compatibility.
+ oneOf:
+ - $ref: '#/definitions/Compatibility'
+ discriminator:
+ propertyName: name
+ mapping:
+ Compatibility: '#/definitions/Compatibility'
+ CodecTypesList:
+ type: object
+ description: Response object for listCodecTypes.
+ properties:
+ codecTypes:
+ type: array
+ description: List of codecTypes.
+ items:
+ type: string
+ Valid:
+ type: object
+ description: Response object for validateSchema api.
+ properties:
+ valid:
+ description: Whether given schema is valid with respect to existing group schemas against the configured validation rules.
+ type: boolean
+ required:
+ - valid
+ CanRead:
+ type: object
+ description: Response object for canRead api.
+ properties:
+ compatible:
+ description: Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.
+ type: boolean
+ required:
+ - compatible
+ GroupHistoryRecord:
+ type: object
+ description: Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.
+ properties:
+ schemaInfo:
+ description: Schema information object.
+ $ref: "#/definitions/SchemaInfo"
+ version:
+ description: Schema version information object.
+ $ref: "#/definitions/VersionInfo"
+ validationRules:
+ description: Schema validation rules applied.
+ $ref: "#/definitions/SchemaValidationRules"
+ timestamp:
+ description: Timestamp when the schema was added.
+ type: integer
+ format: int64
+ schemaString:
+ description: Schema as json string for serialization formats that registry service understands.
+ type: string
+ required:
+ - schemaInfo
+ - version
+ - validationRules
+ - timestamp
+ GroupHistory:
+ type: object
+ properties:
+ history:
+ type: array
+ description: Chronological list of Group History records.
+ items:
+ $ref: "#/definitions/GroupHistoryRecord"
+ AddedTo:
+ type: object
+ description: Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.
+ properties:
+ groups:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/VersionInfo"
+ required:
+ - groups
diff --git a/contract/src/main/swagger/server.config.json b/contract/src/main/swagger/server.config.json
new file mode 100644
index 000000000..f1ac7594b
--- /dev/null
+++ b/contract/src/main/swagger/server.config.json
@@ -0,0 +1,8 @@
+{
+"sourceFolder" : "src/main/java",
+"implFolder" : "src/main/java",
+"modelPackage" : "io.pravega.schemaregistry.contract.generated.rest.model",
+"apiPackage" : "io.pravega.schemaregistry.contract.generated.rest.server.api",
+"library" : "jersey2",
+"hideGenerationTimestamp" : true
+}
diff --git a/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java b/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
new file mode 100644
index 000000000..c724715db
--- /dev/null
+++ b/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.transform;
+
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.Compatibility;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+
+public class ModelHelperTest {
+ @Test
+ public void testDecode() {
+ SerializationFormat type = new SerializationFormat().serializationFormat(SerializationFormat.SerializationFormatEnum.CUSTOM).customTypeName("a");
+ SchemaValidationRules rules = new SchemaValidationRules().rules(Collections.emptyMap());
+ SchemaInfo schema = new SchemaInfo()
+ .type("a").serializationFormat(type).schemaData(new byte[0]).properties(Collections.emptyMap());
+ VersionInfo version = new VersionInfo().type("a").version(1).ordinal(1);
+ Compatibility compatibility = new Compatibility().name(Compatibility.class.getSimpleName())
+ .policy(Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL).backwardTill(version).forwardTill(version);
+ String codecType = "custom";
+
+ // decodes
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = ModelHelper.decode(type);
+ assertEquals(serializationFormat, io.pravega.schemaregistry.contract.data.SerializationFormat.Custom);
+ assertEquals(serializationFormat.getCustomTypeName(), "a");
+
+ io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo = ModelHelper.decode(schema);
+ assertEquals(schemaInfo.getType(), "a");
+ assertEquals(schemaInfo.getSerializationFormat(), serializationFormat);
+ assertNotNull(schemaInfo.getSchemaData());
+ assertNotNull(schemaInfo.getProperties());
+
+ io.pravega.schemaregistry.contract.data.Compatibility compatibilityDecoded = ModelHelper.decode(compatibility);
+ assertEquals(compatibilityDecoded.getCompatibility(), io.pravega.schemaregistry.contract.data.Compatibility.Type.BackwardAndForwardTill);
+
+ io.pravega.schemaregistry.contract.data.SchemaValidationRules rulesDecoded = ModelHelper.decode(rules);
+ assertEquals(rulesDecoded.getRules().size(), 0);
+
+ io.pravega.schemaregistry.contract.data.VersionInfo versionInfo = ModelHelper.decode(version);
+ assertEquals(versionInfo.getType(), version.getType());
+ assertEquals(versionInfo.getVersion(), version.getVersion().intValue());
+
+ io.pravega.schemaregistry.contract.data.EncodingInfo encodingInfo = ModelHelper.decode(new EncodingInfo().schemaInfo(schema).versionInfo(version).codecType(codecType));
+ assertEquals(encodingInfo.getCodecType(), "custom");
+ assertEquals(encodingInfo.getVersionInfo(), versionInfo);
+ assertEquals(encodingInfo.getSchemaInfo(), schemaInfo);
+ io.pravega.schemaregistry.contract.data.SchemaWithVersion schemaWithVersion = ModelHelper.decode(new SchemaWithVersion().schemaInfo(schema).version(version));
+ assertEquals(schemaWithVersion.getVersionInfo(), versionInfo);
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaInfo);
+
+ io.pravega.schemaregistry.contract.data.EncodingId encodingId = ModelHelper.decode(new EncodingId().encodingId(1));
+ assertEquals(encodingId.getId(), 1);
+ }
+
+ @Test
+ public void testEncode() {
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = io.pravega.schemaregistry.contract.data.SerializationFormat.custom("custom");
+ io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo = new io.pravega.schemaregistry.contract.data.SchemaInfo(
+ "name", serializationFormat, ByteBuffer.wrap(new byte[0]), ImmutableMap.of());
+ io.pravega.schemaregistry.contract.data.VersionInfo versionInfo = new io.pravega.schemaregistry.contract.data.VersionInfo("a", 0, 1);
+ io.pravega.schemaregistry.contract.data.Compatibility rule = io.pravega.schemaregistry.contract.data.Compatibility.backwardTillAndForwardTill(
+ new io.pravega.schemaregistry.contract.data.VersionInfo("a", 0, 0),
+ new io.pravega.schemaregistry.contract.data.VersionInfo("a", 1, 1));
+ io.pravega.schemaregistry.contract.data.SchemaValidationRules schemaValidationRules = io.pravega.schemaregistry.contract.data.SchemaValidationRules.of(rule);
+ io.pravega.schemaregistry.contract.data.GroupProperties prop = io.pravega.schemaregistry.contract.data.GroupProperties
+ .builder().serializationFormat(serializationFormat).schemaValidationRules(schemaValidationRules)
+ .allowMultipleTypes(true).properties(ImmutableMap.of()).build();
+ String codecType = "codecType";
+
+ // encode test
+ VersionInfo version = ModelHelper.encode(versionInfo);
+ assertEquals(version.getVersion().intValue(), versionInfo.getVersion());
+ assertEquals(version.getType(), versionInfo.getType());
+
+ SerializationFormat type = ModelHelper.encode(serializationFormat);
+ assertEquals(type.getSerializationFormat(), SerializationFormat.SerializationFormatEnum.CUSTOM);
+
+ SchemaInfo schema = ModelHelper.encode(schemaInfo);
+ assertEquals(schema.getType(), schemaInfo.getType());
+ assertEquals(schema.getProperties(), schemaInfo.getProperties());
+ assertTrue(Arrays.equals(schema.getSchemaData(), schemaInfo.getSchemaData().array()));
+ assertEquals(schema.getSerializationFormat(), type);
+
+ EncodingId encodingId = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.EncodingId(0));
+ assertEquals(encodingId.getEncodingId().intValue(), 0);
+
+ EncodingInfo encodingInfo = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.EncodingInfo(versionInfo, schemaInfo, codecType));
+ assertEquals(encodingInfo.getCodecType(), codecType);
+ assertEquals(encodingInfo.getVersionInfo(), version);
+ assertEquals(encodingInfo.getSchemaInfo(), schema);
+
+ SchemaValidationRules rules = ModelHelper.encode(schemaValidationRules);
+ assertEquals(rules.getRules().size(), 1);
+
+ io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord schemaEvolution = ModelHelper.encode(new GroupHistoryRecord(
+ schemaInfo, versionInfo, schemaValidationRules, 100L, ""));
+ assertEquals(schemaEvolution.getSchemaInfo(), schema);
+ assertEquals(schemaEvolution.getValidationRules(), rules);
+ assertEquals(schemaEvolution.getVersion(), version);
+ assertEquals(schemaEvolution.getTimestamp().longValue(), 100L);
+ assertEquals(schemaEvolution.getSchemaString(), "");
+
+ Compatibility compatibility = ModelHelper.encode(rule);
+ assertEquals(compatibility.getPolicy(), Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL);
+
+ SchemaWithVersion schemaWithVersion = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.SchemaWithVersion(schemaInfo, versionInfo));
+ assertEquals(schemaWithVersion.getSchemaInfo(), schema);
+ assertEquals(schemaWithVersion.getVersion(), version);
+
+ GroupProperties groupProperties = ModelHelper.encode(prop);
+ assertEquals(groupProperties.getSerializationFormat(), type);
+ assertEquals(groupProperties.getSchemaValidationRules(), rules);
+ assertEquals(groupProperties.isAllowMultipleTypes(), prop.isAllowMultipleTypes());
+ assertEquals(groupProperties.getProperties(), prop.getProperties());
+ }
+
+}
From b6348679283c3ea47a41649ba976c34faf2f7bc0 Mon Sep 17 00:00:00 2001
From: Shivesh Ranjan
Date: Sun, 7 Jun 2020 19:43:00 -0700
Subject: [PATCH 02/70] copying over to new fork
Signed-off-by: Shivesh Ranjan
---
build.gradle | 66 +-
.../client/SchemaRegistryClient.java | 358 ++++++++
.../client/SchemaRegistryClientConfig.java | 31 +
.../client/SchemaRegistryClientFactory.java | 25 +
.../client/SchemaRegistryClientImpl.java | 461 ++++++++++
.../client/exceptions/RegistryExceptions.java | 187 ++++
.../client/TestSchemaRegistryClient.java | 612 +++++++++++++
.../common/ContinuationTokenIterator.java | 93 ++
.../pravega/schemaregistry/common/Either.java | 51 ++
.../schemaregistry/common/HashUtil.java | 21 +
.../common/ContinuationTokenIteratorTest.java | 68 ++
.../contract/data/Compatibility.java | 203 ++++
.../contract/data/EncodingId.java | 35 +
.../contract/data/EncodingInfo.java | 33 +
.../contract/data/GroupHistoryRecord.java | 47 +
.../contract/data/GroupProperties.java | 74 ++
.../contract/data/SchemaInfo.java | 62 ++
.../contract/data/SchemaValidationRule.java | 23 +
.../contract/data/SchemaValidationRules.java | 66 ++
.../contract/data/SchemaWithVersion.java | 31 +
.../contract/data/SerializationFormat.java | 45 +
.../contract/data/VersionInfo.java | 47 +
.../generated/rest/model/AddedTo.java | 101 ++
.../generated/rest/model/CanRead.java | 92 ++
.../generated/rest/model/CodecTypesList.java | 101 ++
.../generated/rest/model/Compatibility.java | 216 +++++
.../rest/model/CreateGroupRequest.java | 117 +++
.../generated/rest/model/EncodingId.java | 92 ++
.../generated/rest/model/EncodingInfo.java | 144 +++
.../rest/model/GetEncodingIdRequest.java | 117 +++
.../generated/rest/model/GroupHistory.java | 101 ++
.../rest/model/GroupHistoryRecord.java | 194 ++++
.../generated/rest/model/GroupProperties.java | 179 ++++
.../rest/model/ListGroupsResponse.java | 128 +++
.../generated/rest/model/SchemaInfo.java | 179 ++++
.../rest/model/SchemaValidationRule.java | 92 ++
.../rest/model/SchemaValidationRules.java | 103 +++
.../rest/model/SchemaVersionsList.java | 102 +++
.../rest/model/SchemaWithVersion.java | 119 +++
.../rest/model/SerializationFormat.java | 154 ++++
.../model/UpdateValidationRulesRequest.java | 116 +++
.../contract/generated/rest/model/Valid.java | 92 ++
.../generated/rest/model/ValidateRequest.java | 117 +++
.../generated/rest/model/VersionInfo.java | 142 +++
.../rest/server/api/ApiException.java | 10 +
.../rest/server/api/ApiOriginFilter.java | 22 +
.../rest/server/api/ApiResponseMessage.java | 69 ++
.../generated/rest/server/api/Bootstrap.java | 31 +
.../generated/rest/server/api/GroupsApi.java | 412 +++++++++
.../rest/server/api/GroupsApiService.java | 54 ++
.../rest/server/api/JacksonJsonProvider.java | 18 +
.../rest/server/api/NotFoundException.java | 10 +
.../generated/rest/server/api/SchemasApi.java | 74 ++
.../rest/server/api/SchemasApiService.java | 22 +
.../generated/rest/server/api/StringUtil.java | 42 +
.../factories/GroupsApiServiceFactory.java | 13 +
.../factories/SchemasApiServiceFactory.java | 13 +
.../server/api/impl/GroupsApiServiceImpl.java | 134 +++
.../api/impl/SchemasApiServiceImpl.java | 26 +
.../contract/transform/ModelHelper.java | 243 +++++
.../schemaregistry/contract/v1/ApiV1.java | 554 +++++++++++
contract/src/main/swagger/README.md | 44 +
contract/src/main/swagger/SchemaRegistry.yaml | 867 ++++++++++++++++++
contract/src/main/swagger/server.config.json | 8 +
.../contract/transform/ModelHelperTest.java | 138 +++
settings.gradle | 4 +
66 files changed, 8244 insertions(+), 1 deletion(-)
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
create mode 100644 client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
create mode 100644 client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/Either.java
create mode 100644 common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
create mode 100644 common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
create mode 100644 contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
create mode 100644 contract/src/main/swagger/README.md
create mode 100644 contract/src/main/swagger/SchemaRegistry.yaml
create mode 100644 contract/src/main/swagger/server.config.json
create mode 100644 contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
diff --git a/build.gradle b/build.gradle
index a1f1bb5d6..52125793d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -34,7 +34,6 @@ buildscript {
}
}
dependencies {
- classpath group: 'com.google.protobuf', name:'protobuf-gradle-plugin', version: protobufGradlePlugin
classpath "gradle.plugin.org.nosphere.apache:creadur-rat-gradle:0.3.0"
classpath group: 'org.hidetake', name: 'gradle-ssh-plugin', version: gradleSshPluginVersion
classpath group: 'gradle.plugin.com.github.spotbugs', name: 'spotbugs-gradle-plugin', version: spotbugsPluginVersion
@@ -122,6 +121,71 @@ allprojects {
}
}
+project('common') {
+ dependencies {
+ compile group: 'commons-io', name: 'commons-io', version: commonsioVersion
+ compile group: 'com.google.guava', name: 'guava', version: guavaVersion
+ compile group: 'io.pravega', name: 'pravega-common', version: pravegaVersion
+ //Do NOT add any additional dependencies here.
+ }
+
+ javadoc {
+ title = "Common Libraries"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ options.addBooleanOption("Xdoclint:none", true)
+ }
+}
+
+project('client') {
+ dependencies {
+ compile project(':common')
+ compile project(':contract')
+ compile group: 'org.glassfish.jersey.ext', name: 'jersey-proxy-client', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: jerseyVersion
+ testCompile group: 'org.slf4j', name: 'log4j-over-slf4j', version: slf4jApiVersion
+ testCompile group: 'ch.qos.logback', name: 'logback-classic', version: qosLogbackVersion
+ testCompile group: 'io.pravega', name: 'pravega-test-testcommon', version: pravegaVersion
+ }
+
+ javadoc {
+ title = "Registry Client"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ exclude "**/impl/**";
+ options.addBooleanOption("Xdoclint:all,-reference", true)
+ }
+}
+
+project('contract') {
+ dependencies {
+ compile project(':common')
+ testCompile group: 'org.slf4j', name: 'log4j-over-slf4j', version: slf4jApiVersion
+ testCompile group: 'ch.qos.logback', name: 'logback-classic', version: qosLogbackVersion
+ compile group: 'javax.servlet', name: 'javax.servlet-api', version: javaxServletApiVersion
+ compile(group: 'io.swagger', name : 'swagger-jersey2-jaxrs', version :swaggerJersey2JaxrsVersion) {
+ exclude group: 'com.google.guava', module: 'guava'
+ }
+ compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: jerseyVersion
+ compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: jerseyVersion
+ compile group: 'javax.xml.bind', name: 'jaxb-api', version: jaxbVersion
+ compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: jaxbVersion
+
+ }
+
+ javadoc {
+ title = "Registry Contract"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ exclude "**/impl/**";
+ options.addBooleanOption("Xdoclint:all,-reference", true)
+ }
+}
+
def getProjectVersion() {
String ver = schemaregistryVersion
if (grgit && ver.contains("-SNAPSHOT")) {
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
new file mode 100644
index 000000000..5ed87a3aa
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClient.java
@@ -0,0 +1,358 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+
+import javax.annotation.Nullable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+
+/**
+ * Defines a registry client for interacting with schema registry service.
+ * The implementation of this interface should provide atomicity and read-after-write-consistency guarantees for all the methods.
+ */
+public interface SchemaRegistryClient {
+ /**
+ * Adds a new group. A group refers to the name under which the schemas are registered. A group is identified by a
+ * unique name and has an associated set of group metadata {@link GroupProperties} and a list of codec types and a
+ * versioned history of schemas that were registered under the group.
+ * Add group is idempotent. If the group by the same name already exists the api will return false.
+ *
+ * @param groupId Id for the group that uniquely identifies the group.
+ * @param groupProperties groupProperties Group properties for the group. These include serialization format, validation rules,
+ * and flag to declare whether multiple schemas representing distinct object types can be
+ * registered with the group. Type identify objects of same type. Schema compatibility checks
+ * are always performed for schemas that share same {@link SchemaInfo#type}.
+ * Additionally, a user defined map of properties can be supplied.
+ * @return True indicates if the group was added successfully, false if it exists.
+ * @throws BadArgumentException if the group properties is rejected by service.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean addGroup(String groupId, GroupProperties groupProperties) throws BadArgumentException, UnauthorizedException;
+
+ /**
+ * Removes a group identified by the groupId. This will remove all the codec types and schemas registered under the group.
+ * Remove group is idempotent.
+ *
+ * @param groupId Id for the group that uniquely identifies the group.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void removeGroup(String groupId) throws UnauthorizedException;
+
+ /**
+ * List all groups that the user is authorized on. This returns an iterator where each element is a pair of group
+ * name and group properties.
+ * This iterator can be used to iterate over each element until all elements are exhausted.
+ * The implementation should guarantee that all groups added before and until the iterator returns
+ * {@link Iterator#hasNext()} = true can be iterated over.
+ *
+ * @return map of names of groups with corresponding group properties for all groups.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ Iterator> listGroups() throws UnauthorizedException;
+
+ /**
+ * Get group properties for the group identified by the group id.
+ *
+ * {@link GroupProperties#serializationFormat} which identifies the serialization format is used to describe the schema.
+ * {@link GroupProperties#schemaValidationRules} sets the schema validation policy that needs to be enforced for evolving schemas.
+ * {@link GroupProperties#allowMultipleTypes} that specifies if multiple schemas are allowed to be registered in the group.
+ * Schemas are validated against existing schema versions that have the same {@link SchemaInfo#type}.
+ * {@link GroupProperties#properties} describes generic properties for a group.
+ *
+ * @param groupId Id for the group.
+ * @return Group properties which includes property like Serialization format and compatibility policy.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ GroupProperties getGroupProperties(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Update group's schema validation policy. If previous rules are not supplied, then the update to the rules will be
+ * performed unconditionally. However, if previous rules are supplied, then the update will be performed if and only if
+ * existing {@link GroupProperties#schemaValidationRules} match previous rules.
+ *
+ * @param groupId Id for the group.
+ * @param validationRules New Schema validation rules for the group.
+ * @param previousRules Previous schema validation rules.
+ * @return true if the update was accepted by the service, false if it was rejected because of precondition failure.
+ * Precondition failure can occur if previous rules were specified and they do not match the rules set on the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean updateSchemaValidationRules(String groupId, SchemaValidationRules validationRules, @Nullable SchemaValidationRules previousRules)
+ throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets list of latest schemas for each object types registered under the group. Objects are identified by {@link SchemaInfo#type}.
+ * Schemas are retrieved atomically. So all schemas added before this call will be returned by this call.
+ *
+ * @param groupId Id for the group.
+ * @return List of different objects within the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getSchemas(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Registers schema to the group. Schemas are validated against existing schemas in the group that share the same
+ * {@link SchemaInfo#type}.
+ * If group is configured with {@link GroupProperties#allowMultipleTypes} then multiple schemas with distinct
+ * type {@link SchemaInfo#type} could be registered.
+ * All schemas with same type are assigned monotonically increasing version numbers.
+ * Add schema api is idempotent. If a schema is already registered, its version info is returned by the service.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to add.
+ * @return versionInfo which uniquely identifies where the schema is added in the group. If schema is already registered,
+ * then the existing version info is returned.
+ * @throws SchemaValidationFailedException if the schema is deemed invalid by applying schema validation rules which may
+ * include comparing schema with existing schemas for compatibility in the desired direction.
+ * @throws SerializationMismatchException if serialization format does not match the group's configured serialization format.
+ * @throws MalformedSchemaException for known serialization formats, if the service is unable to parse the schema binary or
+ * for avro and protobuf if the {@link SchemaInfo#type} does not match the name of record/message in the binary.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ VersionInfo addSchema(String groupId, SchemaInfo schemaInfo) throws SchemaValidationFailedException, SerializationMismatchException,
+ MalformedSchemaException, ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Api to delete schema corresponding to the version. Users should be very careful while using this API in production,
+ * esp if the schema has already been used to write the data.
+ * Delete schema api is idempotent.
+ * This does a soft delete of the schema. So getSchemaVersion with the version info will still return the schema.
+ * However, the schema will not participate in any compatibility checks once deleted.
+ * It will not be included in listing schema versions for the group using apis like {@link SchemaRegistryClient#getSchemaVersions}
+ * or {@link SchemaRegistryClient#getGroupHistory} or {@link SchemaRegistryClient#getSchemas} or
+ * {@link SchemaRegistryClient#getLatestSchemaVersion}
+ * If add schema is called again using this deleted schema will result in a new version being assigned to it upon registration.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo Version which uniquely identifies schema within a group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void deleteSchemaVersion(String groupId, VersionInfo versionInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Api to delete schema corresponding to the schemaType and version.
+ * Users should be very careful while using this API in production, esp if the schema has already been used to write the data.
+ * Delete schema api is idempotent.
+ * This does a soft delete of the schema. So getSchemaVersion with the version info will still return the schema.
+ * However, the schema will not participate in any compatibility checks once deleted.
+ * It will not be included in listing schema versions for the group using apis like {@link SchemaRegistryClient#getSchemaVersions}
+ * or {@link SchemaRegistryClient#getGroupHistory} or {@link SchemaRegistryClient#getSchemas} or
+ * {@link SchemaRegistryClient#getLatestSchemaVersion}
+ * If add schema is called again using this deleted schema will result in a new version being assigned to upon registration.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType schemaType that identifies the type of object the schema represents. This should be same as the
+ * value specified in {@link SchemaInfo#type}.
+ * @param version Version number which uniquely identifies schema for the schemaType within a group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void deleteSchemaVersion(String groupId, String schemaType, int version) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets schema corresponding to the version.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo Version which uniquely identifies schema within a group.
+ * @return Schema info corresponding to the version info.
+ * @throws ResourceNotFoundException if group or version is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaInfo getSchemaForVersion(String groupId, VersionInfo versionInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets schema corresponding to the version.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType schemaType as specified in the {@link SchemaInfo#type} while registering the schema.
+ * @param version Version which uniquely identifies schema of schemaType within a group.
+ * @return Schema info corresponding to the version info.
+ * @throws ResourceNotFoundException if group or version is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaInfo getSchemaForVersion(String groupId, String schemaType, int version) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets encoding info against the requested encoding Id. The purpose of encoding info is to uniquely identify the encoding
+ * used on the data at rest. The encoding covers two parts -
+ * 1. Schema that defines the structure of the data and is used for serialization. A specific schema version registered with
+ * registry service is uniquely identified by the corresponding VersionInfo object.
+ * 2. CodecType that is used to encode the serialized data. This would typically be some compression. The codecType
+ * and schema should both be registered with the service and service will generate a unique identifier for each such
+ * pair.
+ * Encoding Info uniquely identifies a combination of a versionInfo and codecType.
+ * EncodingInfo also includes the {@link SchemaInfo} identified by the {@link VersionInfo}.
+ *
+ * @param groupId Id for the group.
+ * @param encodingId Encoding id that uniquely identifies a schema within a group.
+ * @return Encoding info corresponding to the encoding id.
+ * @throws ResourceNotFoundException if group or encoding id is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ EncodingInfo getEncodingInfo(String groupId, EncodingId encodingId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets an encoding id that uniquely identifies a combination of Schema version and codec type.
+ * This encoding id is a 4 byte integer and it can be used to tag the data which is serialized and encoded using the
+ * schema version and codecType identified by this encoding id.
+ * This api is idempotent. And if an encoding id is generated for a version and codec pair, subsequent requests to this
+ * api will return the generated encoding id.
+ * If the schema identified by the version is deleted using {@link SchemaRegistryClient#deleteSchemaVersion} api,
+ * then if the encoding id was already generated for the pair of schema version and codec, then it will be returned.
+ * However, if no encoding id for the versioninfo and codec pair was generated and the schema version was deleted,
+ * then any call to getEncodingId using the deleted versionInfo will throw ResourceNotFoundException.
+ *
+ * @param groupId Id for the group.
+ * @param versionInfo version of schema
+ * @param codecType codec type
+ * @return Encoding id for the pair of version and codec type.
+ * @throws CodecTypeNotRegisteredException if codectype is not registered with the group. Use {@link SchemaRegistryClient#addCodecType}
+ * @throws ResourceNotFoundException if group or version info is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ EncodingId getEncodingId(String groupId, VersionInfo versionInfo, String codecType)
+ throws CodecTypeNotRegisteredException, ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets latest schema and version for the group (or type, if specified).
+ * To get latest schema version for a specific type identified by {@link SchemaInfo#type}, provide the type.
+ * Otherwise if the group is configured to allow multiple schemas {@link GroupProperties#allowMultipleTypes}, then
+ * and type is not specified, then last schema added to the group across all types will be returned.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType Type of object identified by {@link SchemaInfo#type}.
+ *
+ * @return Schema with version for the last schema that was added to the group (or type).
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ SchemaWithVersion getLatestSchemaVersion(String groupId, @Nullable String schemaType)
+ throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets version corresponding to the schema.
+ * For each schema type {@link SchemaInfo#type} and {@link SchemaInfo#serializationFormat} a versionInfo object uniquely
+ * identifies each distinct {@link SchemaInfo#schemaData}.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo SchemaInfo that describes format and structure.
+ * @return VersionInfo corresponding to schema.
+ * @throws ResourceNotFoundException if group is not found or if schema is not registered.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ VersionInfo getVersionForSchema(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets all schemas with corresponding versions for the group (or type, if specified).
+ * For groups configured with {@link GroupProperties#allowMultipleTypes}, the type {@link SchemaInfo#type} should be
+ * supplied to view schemas specific to a type. if type is null, all schemas in the group are returned.
+ * The order in the list matches the order in which schemas were evolved within the group.
+ *
+ * @param groupId Id for the group.
+ * @param schemaType type of object identified by {@link SchemaInfo#type}.
+ * @return Ordered list of schemas with versions and validation rules for all schemas in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getSchemaVersions(String groupId, @Nullable String schemaType) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Checks whether given schema is valid by applying validation rules against previous schemas in the group
+ * subject to current {@link GroupProperties#schemaValidationRules} policy.
+ * This api performs exactly the same validations as {@link SchemaRegistryClient#addSchema(String, SchemaInfo)}
+ * but without registering the schema. This is primarily intended to be used during schema development phase to validate that
+ * the changes to schema are in compliance with validation rules for the group.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to check for validity.
+ * @return A schema is valid if it passes all the {@link GroupProperties#schemaValidationRules}. The rule supported
+ * presently, is Compatibility. If desired compatibility is satisfied by the schema then this api returns true, false otherwise.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean validateSchema(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Checks whether given schema can be used to read by validating it for reads against one or more existing schemas in the group
+ * subject to current {@link GroupProperties#schemaValidationRules} policy.
+ *
+ * @param groupId Id for the group.
+ * @param schemaInfo Schema to check to be used for reads.
+ * @return True if it can be used to read, false otherwise.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ boolean canReadUsing(String groupId, SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * List of codec types used for encoding in the group.
+ *
+ * @param groupId Id for the group.
+ * @return List of codec types used for encoding in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getCodecTypes(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Add new codec type to be used in encoding in the group.
+ *
+ * @param groupId Id for the group.
+ * @param codecType codec type.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ void addCodecType(String groupId, String codecType) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Gets complete schema evolution history of the group with schemas, versions, rules and time for the group.
+ * The order in the list matches the order in which schemas were evolved within the group.
+ * This call is atomic and will get a consistent view at the time when the request is processed on the service.
+ * So all schemas that were added before this call are returned and all schemas that were deleted before this call
+ * are excluded.
+ *
+ * @param groupId Id for the group.
+ * @return Ordered list of schemas with versions and validation rules for all schemas in the group.
+ * @throws ResourceNotFoundException if group is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ List getGroupHistory(String groupId) throws ResourceNotFoundException, UnauthorizedException;
+
+ /**
+ * Finds all groups and corresponding version info for the groups where the supplied schema has been registered.
+ * It is important to note that the same schema type could be part of multiple group, however in each group it
+ * may have gone through a separate evolution. This api simply identifies all groups where the specific schema
+ * (type, format and binary) is used.
+ * The user defined {@link SchemaInfo#properties} is not used for comparison.
+ *
+ * @param schemaInfo Schema info to find references for.
+ * @return Map of group Id to versionInfo identifier for the schema in that group.
+ * @throws ResourceNotFoundException if schema is not found.
+ * @throws UnauthorizedException if the user is unauthorized.
+ */
+ Map getSchemaReferences(SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException;
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
new file mode 100644
index 000000000..66bb39921
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientConfig.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.net.URI;
+
+/**
+ * Registry client configuration used to create registry client.
+ */
+@Data
+@Builder
+public class SchemaRegistryClientConfig {
+ /**
+ * URI for connecting with registry client.
+ */
+ private final URI schemaRegistryUri;
+
+ private SchemaRegistryClientConfig(URI schemaRegistryUri) {
+ this.schemaRegistryUri = schemaRegistryUri;
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
new file mode 100644
index 000000000..caba3d815
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientFactory.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+/**
+ * Factory class for creating Schema Registry client.
+ */
+public class SchemaRegistryClientFactory {
+ /**
+ * Factory method to create Schema Registry Client.
+ *
+ * @param config Configuration for creating registry client.
+ * @return SchemaRegistry client implementation
+ */
+ public static SchemaRegistryClient createRegistryClient(SchemaRegistryClientConfig config) {
+ return new SchemaRegistryClientImpl(config.getSchemaRegistryUri());
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
new file mode 100644
index 000000000..5e46b69c1
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/SchemaRegistryClientImpl.java
@@ -0,0 +1,461 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.pravega.common.Exceptions;
+import io.pravega.common.util.Retry;
+import io.pravega.schemaregistry.common.ContinuationTokenIterator;
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.transform.ModelHelper;
+import io.pravega.schemaregistry.contract.v1.ApiV1;
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.client.proxy.WebResourceFactory;
+
+import javax.annotation.Nullable;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+
+public class SchemaRegistryClientImpl implements SchemaRegistryClient {
+ private static final Retry.RetryAndThrowConditionally RETRY = Retry
+ .withExpBackoff(100, 2, 10, 1000)
+ .retryWhen(x -> Exceptions.unwrap(x) instanceof ConnectionException);
+ private static final int GROUP_LIMIT = 100;
+ private static final int SCHEMA_LIMIT = 10;
+
+ private final ApiV1.GroupsApi groupProxy;
+ private final ApiV1.SchemasApi schemaProxy;
+
+ SchemaRegistryClientImpl(URI uri) {
+ Client client = ClientBuilder.newClient(new ClientConfig());
+ this.groupProxy = WebResourceFactory.newResource(ApiV1.GroupsApi.class, client.target(uri));
+ this.schemaProxy = WebResourceFactory.newResource(ApiV1.SchemasApi.class, client.target(uri));
+ }
+
+ @VisibleForTesting
+ SchemaRegistryClientImpl(ApiV1.GroupsApi groupProxy) {
+ this(groupProxy, null);
+ }
+
+ @VisibleForTesting
+ SchemaRegistryClientImpl(ApiV1.GroupsApi groupProxy, ApiV1.SchemasApi schemaProxy) {
+ this.groupProxy = groupProxy;
+ this.schemaProxy = schemaProxy;
+ }
+
+ @Override
+ public boolean addGroup(String groupId, GroupProperties groupProperties) {
+ return withRetry(() -> {
+ CreateGroupRequest request = new CreateGroupRequest().groupName(groupId).groupProperties(ModelHelper.encode(groupProperties));
+ Response response = groupProxy.createGroup(request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return true;
+ case CONFLICT:
+ return false;
+ case BAD_REQUEST:
+ throw new BadArgumentException("Group properties invalid. Verify that schema validation rules include compatibility.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to add the group.");
+ }
+ });
+ }
+
+ @Override
+ public void removeGroup(String groupId) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteGroup(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case NO_CONTENT:
+ return;
+ default:
+ throw new InternalServerError("Internal Service error. Failed to remove the group.");
+ }
+ });
+ }
+
+ @Override
+ public Iterator> listGroups() {
+ final Function>>> function =
+ continuationToken -> {
+ ListGroupsResponse entity = getListGroupsResponse(continuationToken);
+ List> map = new LinkedList<>();
+ for (Map.Entry entry : entity.getGroups().entrySet()) {
+ ModelHelper.decode(entry.getValue().getSerializationFormat());
+ map.add(new AbstractMap.SimpleEntry<>(entry.getKey(), ModelHelper.decode(entry.getValue())));
+ }
+ return new AbstractMap.SimpleEntry<>(entity.getContinuationToken(), map);
+ };
+
+ return new ContinuationTokenIterator<>(function, null);
+ }
+
+ private ListGroupsResponse getListGroupsResponse(String continuationToken) {
+ return withRetry(() -> {
+ Response response = groupProxy.listGroups(continuationToken, GROUP_LIMIT);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(ListGroupsResponse.class);
+ default:
+ throw new InternalServerError("Internal Service error. Failed to list groups.");
+ }
+ });
+ }
+
+ @Override
+ public GroupProperties getGroupProperties(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getGroupProperties(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to list groups.");
+ }
+ });
+ }
+
+ @Override
+ public boolean updateSchemaValidationRules(String groupId, SchemaValidationRules validationRules, @Nullable SchemaValidationRules previousRules) {
+ return withRetry(() -> {
+ UpdateValidationRulesRequest request = new UpdateValidationRulesRequest()
+ .validationRules(ModelHelper.encode(validationRules));
+ if (previousRules != null) {
+ request.setPreviousRules(ModelHelper.encode(previousRules));
+ }
+
+ Response response = groupProxy.updateSchemaValidationRules(groupId, request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CONFLICT:
+ return false;
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ case OK:
+ return true;
+ default:
+ throw new InternalServerError("Internal Service error. Failed to update schema validation rules.");
+ }
+ });
+ }
+
+ @Override
+ public List getSchemas(String groupId) {
+ return latestSchemas(groupId, null);
+ }
+
+ private List latestSchemas(String groupId, String type) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemas(groupId, type);
+ SchemaVersionsList objectsList = response.readEntity(SchemaVersionsList.class);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return objectsList.getSchemas().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get object types.");
+ }
+ });
+ }
+
+ @Override
+ public VersionInfo addSchema(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ Response response = groupProxy.addSchema(groupId, ModelHelper.encode(schemaInfo));
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ case CONFLICT:
+ throw new SchemaValidationFailedException("Schema is incompatible.");
+ case EXPECTATION_FAILED:
+ throw new SerializationMismatchException("Serialization format disallowed.");
+ case BAD_REQUEST:
+ throw new MalformedSchemaException("Schema is malformed. Verify the schema data and type");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to addSchema.");
+ }
+ });
+ }
+
+ @Override
+ public void deleteSchemaVersion(String groupId, VersionInfo versionInfo) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteSchemaFromVersionOrdinal(groupId, versionInfo.getOrdinal());
+ if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
+ throw new ResourceNotFoundException("Group not found.");
+ } else if (response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) {
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public void deleteSchemaVersion(String groupId, String schemaType, int version) {
+ withRetry(() -> {
+ Response response = groupProxy.deleteSchemaVersion(groupId, schemaType, version);
+ if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
+ throw new ResourceNotFoundException("Group not found.");
+ } else if (response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) {
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaInfo getSchemaForVersion(String groupId, VersionInfo versionInfo) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaFromVersionOrdinal(groupId, versionInfo.getOrdinal());
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaInfo getSchemaForVersion(String groupId, String schemaType, int version) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaFromVersion(groupId, schemaType, version);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema.");
+ }
+ });
+ }
+
+ @Override
+ public EncodingInfo getEncodingInfo(String groupId, EncodingId encodingId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getEncodingInfo(groupId, encodingId.getId());
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Encoding not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get encoding info.");
+ }
+ });
+ }
+
+ @Override
+ public EncodingId getEncodingId(String groupId, VersionInfo versionInfo, String codecType) {
+ return withRetry(() -> {
+ GetEncodingIdRequest getEncodingIdRequest = new GetEncodingIdRequest();
+ getEncodingIdRequest.codecType(codecType)
+ .versionInfo(ModelHelper.encode(versionInfo));
+ Response response = groupProxy.getEncodingId(groupId, getEncodingIdRequest);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.EncodingId.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getEncodingId failed. Either Group or Version does not exist.");
+ case PRECONDITION_FAILED:
+ throw new CodecTypeNotRegisteredException(String.format("Codec type %s not registered.", codecType));
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get encoding info.");
+ }
+ });
+ }
+
+ @Override
+ public SchemaWithVersion getLatestSchemaVersion(String groupId, @Nullable String schemaType) {
+ List list = latestSchemas(groupId, schemaType);
+ if (schemaType == null) {
+ return list.stream().max(Comparator.comparingInt(x -> x.getVersionInfo().getOrdinal())).orElse(null);
+ } else {
+ return list.get(0);
+ }
+ }
+
+ @Override
+ public List getSchemaVersions(String groupId, @Nullable String schemaType) {
+ return withRetry(() -> {
+ Response response = groupProxy.getSchemaVersions(groupId, schemaType);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ SchemaVersionsList schemaList = response.readEntity(SchemaVersionsList.class);
+ return schemaList.getSchemas().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getSchemaVersions failed. Group does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema versions for group.");
+ }
+ });
+ }
+
+ @Override
+ public List getGroupHistory(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getGroupHistory(groupId);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory history = response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory.class);
+ return history.getHistory().stream().map(ModelHelper::decode).collect(Collectors.toList());
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getGroupHistory failed. Either Group or Version does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema evolution history for group.");
+ }
+ });
+ }
+
+ @Override
+ public Map getSchemaReferences(SchemaInfo schemaInfo) throws ResourceNotFoundException, UnauthorizedException {
+ return withRetry(() -> {
+ Response response = schemaProxy.getSchemaReferences(ModelHelper.encode(schemaInfo));
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ io.pravega.schemaregistry.contract.generated.rest.model.AddedTo addedTo = response
+ .readEntity(io.pravega.schemaregistry.contract.generated.rest.model.AddedTo.class);
+ return addedTo.getGroups().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, x -> ModelHelper.decode(x.getValue())));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("getSchemaReferences failed. Either Group or Version does not exist.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema evolution history for group.");
+ }
+ });
+ }
+
+ @Override
+ public VersionInfo getVersionForSchema(String groupId, SchemaInfo schema) {
+ return withRetry(() -> {
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo schemaInfo = ModelHelper.encode(schema);
+
+ Response response = groupProxy.getSchemaVersion(groupId, schemaInfo);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return ModelHelper.decode(response.readEntity(io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class));
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error. Failed to get schema version.");
+ }
+ });
+ }
+
+ @Override
+ public boolean validateSchema(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ ValidateRequest validateRequest = new ValidateRequest()
+ .schemaInfo(ModelHelper.encode(schemaInfo));
+ Response response = groupProxy.validate(groupId, validateRequest);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(Valid.class).isValid();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Internal Service error.");
+ }
+ });
+ }
+
+ @Override
+ public boolean canReadUsing(String groupId, SchemaInfo schemaInfo) {
+ return withRetry(() -> {
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo request = ModelHelper.encode(schemaInfo);
+ Response response = groupProxy.canRead(groupId, request);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return response.readEntity(CanRead.class).isCompatible();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Schema not found.");
+ default:
+ throw new InternalServerError("Internal Service error.");
+ }
+ });
+ }
+
+ @Override
+ public List getCodecTypes(String groupId) {
+ return withRetry(() -> {
+ Response response = groupProxy.getCodecTypesList(groupId);
+ CodecTypesList list = response.readEntity(CodecTypesList.class);
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case OK:
+ return list.getCodecTypes();
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Failed to get codecTypes. Internal server error.");
+ }
+ });
+ }
+
+ @Override
+ public void addCodecType(String groupId, String codecType) {
+ withRetry(() -> {
+ Response response = groupProxy.addCodecType(groupId, codecType);
+
+ switch (Response.Status.fromStatusCode(response.getStatus())) {
+ case CREATED:
+ return;
+ case NOT_FOUND:
+ throw new ResourceNotFoundException("Group not found.");
+ default:
+ throw new InternalServerError("Failed to add codec type. Internal server error.");
+ }
+ });
+ }
+
+ private T withRetry(Supplier supplier) {
+ return RETRY.run(supplier::get);
+ }
+
+ private void withRetry(Runnable runnable) {
+ RETRY.run(() -> {
+ runnable.run();
+ return null;
+ });
+ }
+}
diff --git a/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java b/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
new file mode 100644
index 000000000..7bbb28966
--- /dev/null
+++ b/client/src/main/java/io/pravega/schemaregistry/client/exceptions/RegistryExceptions.java
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client.exceptions;
+
+import com.google.common.base.Preconditions;
+import io.pravega.schemaregistry.contract.data.GroupProperties;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+public class RegistryExceptions extends RuntimeException {
+ /**
+ * Enum to describe the type of exception.
+ */
+ public enum Type {
+ UNAUTHORIZED,
+ BAD_ARGUMENT,
+ PRECONDITION_FAILED,
+ CODEC_NOT_FOUND,
+ MALFORMED_SCHEMA,
+ INCOMPATIBLE_SCHEMA,
+ RESOURCE_NOT_FOUND,
+ SERIALIZATION_FORMAT_MISMATCH,
+ CONNECTION_ERROR,
+ INTERNAL_SERVER_ERROR
+ }
+
+ /**
+ * Trait to identify whether an exception is retryable or not.
+ */
+ public interface RetryableException {
+ }
+
+ /**
+ * Construct a StoreException.
+ *
+ * @param errorMessage The detailed error message.
+ */
+ public RegistryExceptions(final String errorMessage) {
+ super(errorMessage);
+ }
+
+ /**
+ * Factory method to construct Store exceptions.
+ *
+ * @param type Type of Exception.
+ * @param errorMessage The detailed error message.
+ * @return Instance of type of StoreException.
+ */
+ public static RegistryExceptions create(final Type type, final String errorMessage) {
+ Preconditions.checkArgument(errorMessage != null && !errorMessage.isEmpty(),
+ "Either cause or errorMessage should be non-empty");
+ RegistryExceptions exception;
+ switch (type) {
+ case UNAUTHORIZED:
+ exception = new UnauthorizedException(errorMessage);
+ break;
+ case BAD_ARGUMENT:
+ exception = new BadArgumentException(errorMessage);
+ break;
+ case PRECONDITION_FAILED:
+ exception = new PreconditionFailedException(errorMessage);
+ break;
+ case CODEC_NOT_FOUND:
+ exception = new CodecTypeNotRegisteredException(errorMessage);
+ break;
+ case INCOMPATIBLE_SCHEMA:
+ exception = new SchemaValidationFailedException(errorMessage);
+ break;
+ case RESOURCE_NOT_FOUND:
+ exception = new ResourceNotFoundException(errorMessage);
+ break;
+ case SERIALIZATION_FORMAT_MISMATCH:
+ exception = new SerializationMismatchException(errorMessage);
+ break;
+ case CONNECTION_ERROR:
+ exception = new ConnectionException(errorMessage);
+ break;
+ case INTERNAL_SERVER_ERROR:
+ exception = new InternalServerError(errorMessage);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid exception type");
+ }
+ return exception;
+ }
+
+ /**
+ * User is unauthorized to perform requested action.
+ */
+ public static class UnauthorizedException extends RegistryExceptions {
+ public UnauthorizedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Service rejected the supplied arguments with bad argument exception.
+ */
+ public static class BadArgumentException extends RegistryExceptions {
+ public BadArgumentException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Service rejected the request because the expected precondition for the requested action was not satisfied.
+ */
+ public static class PreconditionFailedException extends RegistryExceptions {
+ public PreconditionFailedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The requested codecType is not added to the group.
+ */
+ public static class CodecTypeNotRegisteredException extends RegistryExceptions {
+ public CodecTypeNotRegisteredException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Schema is malformed. Verify the schema data and type.
+ */
+ public static class MalformedSchemaException extends RegistryExceptions {
+ public MalformedSchemaException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The schema validation failed as it was validated against the ValidationRules set for the group.
+ */
+ public static class SchemaValidationFailedException extends RegistryExceptions {
+ public SchemaValidationFailedException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Requested resource not found.
+ */
+ public static class ResourceNotFoundException extends RegistryExceptions {
+ public ResourceNotFoundException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Serialization format is not allowed for the group. Check {@link SchemaInfo#serializationFormat} with
+ * {@link GroupProperties#serializationFormat}.
+ */
+ public static class SerializationMismatchException extends RegistryExceptions {
+ public SerializationMismatchException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * Exception type due to failure in connecting to the service.
+ */
+ public static class ConnectionException extends RegistryExceptions implements RetryableException {
+ public ConnectionException(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+
+ /**
+ * The request processing failed on the service.
+ */
+ public static class InternalServerError extends RegistryExceptions implements RetryableException {
+ public InternalServerError(String errorMessage) {
+ super(errorMessage);
+ }
+ }
+}
diff --git a/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java b/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
new file mode 100644
index 000000000..f4427b183
--- /dev/null
+++ b/client/src/test/java/io/pravega/schemaregistry/client/TestSchemaRegistryClient.java
@@ -0,0 +1,612 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.client;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import io.pravega.schemaregistry.contract.data.Compatibility;
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.data.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.data.SerializationFormat;
+import io.pravega.schemaregistry.contract.data.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.transform.ModelHelper;
+import io.pravega.schemaregistry.contract.v1.ApiV1;
+import io.pravega.test.common.AssertExtensions;
+import lombok.val;
+import org.junit.Test;
+
+import javax.ws.rs.core.Response;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static io.pravega.schemaregistry.client.exceptions.RegistryExceptions.*;
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+public class TestSchemaRegistryClient {
+ @Test
+ public void testGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+
+ // add group
+ // 1. success response code
+ io.pravega.schemaregistry.contract.data.GroupProperties groupProperties = new io.pravega.schemaregistry.contract.data.GroupProperties(
+ SerializationFormat.Avro, SchemaValidationRules.of(Compatibility.backward()), true);
+ doReturn(response).when(proxy).createGroup(any());
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ boolean addGroup = client.addGroup("grp1", groupProperties);
+ assertTrue(addGroup);
+
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ addGroup = client.addGroup("grp1", groupProperties);
+ assertFalse(addGroup);
+
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("Exception should have been thrown",
+ () -> client.addGroup("grp1", groupProperties),
+ e -> e instanceof InternalServerError);
+ reset(response);
+
+ // list groups
+ doReturn(response).when(proxy).listGroups(null, 100);
+ Response response2 = mock(Response.class);
+ doReturn(response2).when(proxy).listGroups("token", 100);
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ doReturn(Response.Status.OK.getStatusCode()).when(response2).getStatus();
+ GroupProperties mygroup = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ String groupName = "mygroup";
+ ListGroupsResponse groupList = new ListGroupsResponse().groups(Collections.singletonMap(groupName, mygroup)).continuationToken("token");
+ doReturn(groupList).when(response).readEntity(eq(ListGroupsResponse.class));
+ doReturn(new ListGroupsResponse().groups(Collections.emptyMap()).continuationToken("token")).when(response2).readEntity(eq(ListGroupsResponse.class));
+
+ val groups = Lists.newArrayList(client.listGroups());
+ assertEquals(1, groups.size());
+ assertTrue(groups.stream().anyMatch(x -> x.getKey().equals(groupName)));
+ Map.Entry group =
+ groups.stream().filter(x -> x.getKey().equals(groupName)).findAny().orElseThrow(RuntimeException::new);
+ assertEquals(group.getValue().getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(group.getValue().getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()), Compatibility.backward());
+
+ reset(response);
+ }
+
+ @Test
+ public void testListGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ GroupProperties mygroup = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ String groupId = "mygroup";
+ ListGroupsResponse groupList = new ListGroupsResponse().groups(Collections.singletonMap(groupId, mygroup)).continuationToken("token");
+ ListGroupsResponse groupList2 = new ListGroupsResponse().groups(Collections.emptyMap()).continuationToken("token");
+ doReturn(response).when(proxy).listGroups(null, 100);
+ Response response2 = mock(Response.class);
+ doReturn(response2).when(proxy).listGroups("token", 100);
+ doReturn(Response.Status.OK.getStatusCode()).when(response2).getStatus();
+
+ doReturn(groupList).when(response).readEntity(eq(ListGroupsResponse.class));
+ doReturn(groupList2).when(response2).readEntity(eq(ListGroupsResponse.class));
+ val groups = Lists.newArrayList(client.listGroups());
+ assertEquals(1, groups.size());
+ assertTrue(groups.stream().anyMatch(x -> x.getKey().equals(groupId)));
+ Map.Entry group =
+ groups.stream().filter(x -> x.getKey().equals(groupId)).findAny().orElseThrow(RuntimeException::new);
+ assertEquals(group.getValue().getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(group.getValue().getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()), Compatibility.backward());
+
+ // Runtime Exception
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("Exception should have been thrown", () -> Lists.newArrayList(client.listGroups()), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testRemoveGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).deleteGroup(anyString());
+ doReturn(Response.Status.NO_CONTENT.getStatusCode()).when(response).getStatus();
+
+ client.removeGroup("mygroup");
+
+ // not OK response
+ doReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.removeGroup("mygroup"),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetGroupProperties() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getGroupProperties(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ GroupProperties mygroup
+ = new GroupProperties().properties(Collections.emptyMap())
+ .serializationFormat(new io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat()
+ .serializationFormat(
+ io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat.SerializationFormatEnum.ANY))
+ .schemaValidationRules(ModelHelper.encode(SchemaValidationRules.of(Compatibility.backward())))
+ .allowMultipleTypes(false);
+ doReturn(mygroup).when(response).readEntity(eq(GroupProperties.class));
+ io.pravega.schemaregistry.contract.data.GroupProperties groupProperties = client.getGroupProperties("mygroup");
+ assertEquals(groupProperties.getSerializationFormat(), SerializationFormat.Any);
+ assertEquals(groupProperties.getSchemaValidationRules().getRules().get(Compatibility.class.getSimpleName()),
+ Compatibility.backward());
+ // ResourceNotFoundException
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getGroupProperties(
+ "mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getGroupProperties(
+ "mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testUpdateSchemaValidationRules() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).updateSchemaValidationRules(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.backward());
+ client.updateSchemaValidationRules("mygroup", schemaValidationRules, null);
+ assertEquals(response.getStatus(), Response.Status.OK.getStatusCode());
+ // Precondition Failed
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ assertFalse(client.updateSchemaValidationRules("mygroup", schemaValidationRules, null));
+ // NotFound exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.updateSchemaValidationRules("mygroup", schemaValidationRules, null),
+ e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.updateSchemaValidationRules("mygroup", schemaValidationRules, null),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testSchemasApi() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemas(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema1", 5, 5);
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion schemaVersion = new io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion()
+ .schemaInfo(ModelHelper.encode(schemaInfo)).version(ModelHelper.encode(versionInfo));
+ SchemaVersionsList schemaList = new SchemaVersionsList();
+ schemaList.addSchemasItem(schemaVersion);
+ doReturn(schemaList).when(response).readEntity(SchemaVersionsList.class);
+ List output = client.getSchemas("mygroup");
+ assertEquals(1, output.size());
+ assertEquals("schema1", output.get(0).getSchemaInfo().getType());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getSchemas("mygroup"),
+ e -> e instanceof ResourceNotFoundException);
+ // Runtime exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown", () -> client.getSchemas("mygroup"),
+ e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testAddSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).addSchema(anyString(), any());
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo versionInfo =
+ new io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo().version(
+ 5).type("schema2").ordinal(5);
+ doReturn(versionInfo).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class);
+ VersionInfo versionInfo1 = client.addSchema("mygroup", schemaInfo);
+ assertEquals(5, versionInfo1.getVersion());
+ assertEquals("schema2", versionInfo1.getType());
+ assertEquals(5, versionInfo1.getOrdinal());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ // SchemaIncompatible exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof SchemaValidationFailedException);
+ // SerializationFormatInvalid Exception
+ doReturn(Response.Status.EXPECTATION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof SerializationMismatchException);
+ //Runtime Exception
+ doReturn(Response.Status.BAD_GATEWAY.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaFromVersionOrdinal(anyString(), anyInt());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat serializationFormat = ModelHelper.encode(SerializationFormat.custom("custom"));
+ byte[] schemaData = new byte[0];
+
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo schemaInfo =
+ new io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo()
+ .schemaData(schemaData).type("schema1").serializationFormat(serializationFormat).properties(Collections.emptyMap());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ doReturn(schemaInfo).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo.class);
+ SchemaInfo schemaInfo1 = client.getSchemaForVersion("mygroup", versionInfo);
+ assertEquals(schemaInfo.getType(), schemaInfo1.getType());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getSchemaForVersion("mygroup", versionInfo), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getSchemaForVersion("mygroup", versionInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetEncodingInfo() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getEncodingInfo(anyString(), anyInt());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ String codecType = "gzip";
+ EncodingInfo encodingInfo = new EncodingInfo(versionInfo, schemaInfo, codecType);
+ EncodingId encodingId = new EncodingId(5);
+ doReturn(ModelHelper.encode(encodingInfo)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo.class);
+ EncodingInfo encodingInfo1 = client.getEncodingInfo("mygroup", encodingId);
+ assertEquals(encodingInfo.getCodecType(), encodingInfo1.getCodecType());
+ assertEquals(encodingInfo.getSchemaInfo(), encodingInfo1.getSchemaInfo());
+ assertEquals(encodingInfo.getVersionInfo(), encodingInfo1.getVersionInfo());
+ // NotFound exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingInfo("mygroup", encodingId), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingInfo("mygroup", encodingId), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetEncodingId() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getEncodingId(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingId encodingId = ModelHelper.encode(new EncodingId(5));
+ doReturn(encodingId).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.EncodingId.class);
+ EncodingId encodingId1 = client.getEncodingId("mygroup", versionInfo, codecType);
+ assertEquals(encodingId.getEncodingId().intValue(), encodingId1.getId());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof ResourceNotFoundException);
+ // StringNotFound Exception
+ doReturn(Response.Status.PRECONDITION_FAILED.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof CodecTypeNotRegisteredException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getEncodingId("mygroup", versionInfo, codecType), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetLatestSchemaForGroup() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemas(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ SchemaWithVersion schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ SchemaVersionsList schemaWithVersions = new SchemaVersionsList().schemas(Collections.singletonList(ModelHelper.encode(schemaWithVersion)));
+ doReturn(schemaWithVersions).when(response).readEntity(
+ SchemaVersionsList.class);
+ SchemaWithVersion schemaWithVersion1 = client.getLatestSchemaVersion("mygroup", null);
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaWithVersion1.getSchemaInfo());
+ assertEquals(schemaWithVersion.getVersionInfo(), schemaWithVersion1.getVersionInfo());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", null), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", null), e -> e instanceof InternalServerError);
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ versionInfo = new VersionInfo("schema2", 5, 5);
+ serializationFormat = SerializationFormat.custom("custom");
+ schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ doReturn(ModelHelper.encode(schemaWithVersion)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion.class);
+ schemaWithVersion1 = client.getLatestSchemaVersion("mygroup", "myobject");
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaWithVersion1.getSchemaInfo());
+ assertEquals(schemaWithVersion.getVersionInfo(), schemaWithVersion1.getVersionInfo());
+ // NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", "myobject"), e -> e instanceof ResourceNotFoundException);
+ // Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getLatestSchemaVersion("mygroup", "myobject"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGroupEvolutionHistory() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getGroupHistory(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.backward());
+ GroupHistoryRecord groupHistoryRecord = new io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord()
+ .schemaInfo(ModelHelper.encode(schemaInfo)).version(ModelHelper.encode(versionInfo))
+ .validationRules(ModelHelper.encode(schemaValidationRules)).timestamp(100L).schemaString("");
+ GroupHistory history = new GroupHistory();
+ history.addHistoryItem(groupHistoryRecord);
+ doReturn(history).when(response).readEntity(GroupHistory.class);
+ List groupHistoryList = client.getGroupHistory("mygroup");
+ assertEquals(1, groupHistoryList.size());
+ assertEquals(schemaValidationRules, groupHistoryList.get(0).getRules());
+ assertEquals(schemaInfo, groupHistoryList.get(0).getSchema());
+ assertEquals(versionInfo, groupHistoryList.get(0).getVersion());
+ assertEquals(100L, groupHistoryList.get(0).getTimestamp());
+ assertEquals("", groupHistoryList.get(0).getSchemaString());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getGroupHistory("mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getGroupHistory("mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchemaVersion() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaVersion(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ doReturn(ModelHelper.encode(versionInfo)).when(response).readEntity(
+ io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo.class);
+ VersionInfo versionInfo1 = client.getVersionForSchema("mygroup", schemaInfo);
+ assertEquals(versionInfo.getType(), versionInfo1.getType());
+ assertEquals(versionInfo.getVersion(), versionInfo1.getVersion());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getVersionForSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getVersionForSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetSchemaVersions() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getSchemaVersions(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ VersionInfo versionInfo = new VersionInfo("schema2", 5, 5);
+ SchemaWithVersion schemaWithVersion = new SchemaWithVersion(schemaInfo, versionInfo);
+ SchemaVersionsList list = new SchemaVersionsList().schemas(Collections.singletonList(ModelHelper.encode(schemaWithVersion)));
+ doReturn(list).when(response).readEntity(SchemaVersionsList.class);
+ List result = Lists.newArrayList(client.getSchemaVersions("mygroup", null));
+ assertEquals(result.size(), 1);
+ assertEquals(versionInfo, result.get(0).getVersionInfo());
+ assertEquals(schemaInfo, result.get(0).getSchemaInfo());
+
+ result = Lists.newArrayList(client.getSchemaVersions("mygroup", schemaInfo.getType()));
+ assertEquals(result.size(), 1);
+ assertEquals(versionInfo, result.get(0).getVersionInfo());
+ assertEquals(schemaInfo, result.get(0).getSchemaInfo());
+
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> Lists.newArrayList(client.getSchemaVersions("mygroup", null)),
+ e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> Lists.newArrayList(client.getSchemaVersions("mygroup", null)), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testValidateSchema() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).validate(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ Valid valid = new Valid().valid(Boolean.TRUE);
+ doReturn(valid).when(response).readEntity(Valid.class);
+ Boolean valid1 = client.validateSchema("mygroup", schemaInfo);
+ assertEquals(valid.isValid(), valid1);
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.validateSchema("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.validateSchema("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testCanRead() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).canRead(anyString(), any());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ SerializationFormat serializationFormat = SerializationFormat.custom("custom");
+ ByteBuffer schemaData = ByteBuffer.wrap(new byte[0]);
+
+ SchemaInfo schemaInfo = new SchemaInfo("schema1", serializationFormat, schemaData, ImmutableMap.of());
+ CanRead canRead = new CanRead().compatible(Boolean.TRUE);
+ doReturn(canRead).when(response).readEntity(CanRead.class);
+ Boolean canRead1 = client.canReadUsing("mygroup", schemaInfo);
+ assertEquals(canRead.isCompatible(), canRead1);
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.canReadUsing("mygroup", schemaInfo), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.canReadUsing("mygroup", schemaInfo), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testGetCodecTypes() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).getCodecTypesList(anyString());
+
+ doReturn(Response.Status.OK.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ String codecType1 = "snappy";
+ CodecTypesList codecTypesList = new CodecTypesList();
+ codecTypesList.addCodecTypesItem(codecType);
+ codecTypesList.addCodecTypesItem(codecType1);
+ doReturn(codecTypesList).when(response).readEntity(CodecTypesList.class);
+ List codecTypesList1 = client.getCodecTypes("mygroup");
+ assertEquals(2, codecTypesList1.size());
+ assertEquals("gzip", codecTypesList1.get(0));
+ assertEquals("snappy", codecTypesList1.get(1));
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getCodecTypes("mygroup"), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.getCodecTypes("mygroup"), e -> e instanceof InternalServerError);
+ }
+
+ @Test
+ public void testAddCodecType() {
+ ApiV1.GroupsApi proxy = mock(ApiV1.GroupsApi.class);
+ SchemaRegistryClientImpl client = new SchemaRegistryClientImpl(proxy);
+ Response response = mock(Response.class);
+ doReturn(response).when(proxy).addCodecType(anyString(), any());
+
+ doReturn(Response.Status.CREATED.getStatusCode()).when(response).getStatus();
+ String codecType = "gzip";
+ client.addCodecType("mygroup", codecType);
+ assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+ //NotFound Exception
+ doReturn(Response.Status.NOT_FOUND.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addCodecType("mygroup", codecType), e -> e instanceof ResourceNotFoundException);
+ //Runtime Exception
+ doReturn(Response.Status.CONFLICT.getStatusCode()).when(response).getStatus();
+ AssertExtensions.assertThrows("An exception should have been thrown",
+ () -> client.addCodecType("mygroup", codecType), e -> e instanceof InternalServerError);
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java b/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
new file mode 100644
index 000000000..ff998e60d
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/ContinuationTokenIterator.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import lombok.Synchronized;
+
+import javax.annotation.concurrent.GuardedBy;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.Function;
+
+/**
+ * Continuation token iterator which fetches a batch of values using the loading function. Once those values have been
+ * iterated over, it uses the continuation token to read more values using the loading function until the function does
+ * not return a value.
+ * @param Type of value.
+ * @param Type of continuation token.
+ */
+public class ContinuationTokenIterator implements Iterator {
+ @GuardedBy("$lock")
+ private final Queue queue;
+ private final Function>> loadingFunction;
+ @GuardedBy("lock")
+ private Token token;
+ @GuardedBy("$lock")
+ private T next;
+ @GuardedBy("$lock")
+ private boolean canHaveNext;
+ @GuardedBy("$lock")
+ private final Set tokens;
+
+ public ContinuationTokenIterator(Function>> loadingFunction, Token tokenIdentity) {
+ this.loadingFunction = loadingFunction;
+ this.queue = new LinkedBlockingQueue();
+ this.token = tokenIdentity;
+ this.canHaveNext = true;
+ this.next = null;
+ this.tokens = new HashSet<>();
+ }
+
+ @Synchronized
+ private void load() {
+ next = next == null ? queue.poll() : next;
+ while (next == null && canHaveNext) {
+ Map.Entry> result = loadingFunction.apply(token);
+ boolean tokenUpdated = result.getKey() != null && !tokens.contains(result.getKey());
+ if (result.getKey() != null) {
+ tokens.add(result.getKey());
+ }
+ token = result.getKey();
+
+ queue.addAll(result.getValue());
+ next = queue.poll();
+ if (next == null) {
+ canHaveNext = tokenUpdated;
+ }
+ }
+ }
+
+ @Synchronized
+ @Override
+ public boolean hasNext() {
+ load();
+ return canHaveNext;
+ }
+
+ @Synchronized
+ @Override
+ public T next() {
+ load();
+ if (next != null) {
+ T retVal = next;
+ next = null;
+ return retVal;
+ } else {
+ assert !canHaveNext;
+ throw new NoSuchElementException();
+ }
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/Either.java b/common/src/main/java/io/pravega/schemaregistry/common/Either.java
new file mode 100644
index 000000000..212ad99fe
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/Either.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.base.Preconditions;
+import lombok.Data;
+
+/**
+ * A holder object consisting of either of two elements.
+ *
+ * The objects could be of any type. Exactly one of the values will exist while the other will be null.
+ * If a mutable object is stored in 'Either', then 'Either' itself effectively becomes mutable.
+ *
+ * @param the left element type.
+ * @param the right element type.
+ */
+@Data
+public class Either {
+ private final T left;
+ private final K right;
+
+ private Either(T left, K right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ public static Either left(T t) {
+ Preconditions.checkNotNull(t);
+ return new Either(t, null);
+ }
+
+ public static Either right(K k) {
+ Preconditions.checkNotNull(k);
+ return new Either(null, k);
+ }
+
+ public boolean isLeft() {
+ return left != null;
+ }
+
+ public boolean isRight() {
+ return right != null;
+ }
+}
diff --git a/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java b/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
new file mode 100644
index 000000000..3875cbb44
--- /dev/null
+++ b/common/src/main/java/io/pravega/schemaregistry/common/HashUtil.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+
+public class HashUtil {
+ private static final HashFunction HASH = Hashing.murmur3_128();
+
+ public static long getFingerprint(byte[] bytes) {
+ return HASH.hashBytes(bytes).asLong();
+ }
+}
diff --git a/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java b/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
new file mode 100644
index 000000000..89989512a
--- /dev/null
+++ b/common/src/test/java/io/pravega/schemaregistry/common/ContinuationTokenIteratorTest.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.common;
+
+import com.google.common.collect.Lists;
+import lombok.Data;
+import org.junit.Test;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.Function;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class ContinuationTokenIteratorTest {
+ @Test
+ public void test() {
+ // 1. call method 1st call returns - list of 5 items + new token
+ // verify that call method is not called until all 10 are read.
+ // 2. call returns empty list + new token
+ // 3. call returns empty list + new token
+ // 4. call returns list of 10 items + new token
+ // verify that we consume 10 items without calling the callmethod
+ // 5. call returns empty list + same token. --> this should exit
+ Queue responses = spy(new LinkedBlockingQueue<>());
+ responses.add(new ListWithToken(Lists.newArrayList(1, 2, 3, 4, 5), "1"));
+ responses.add(new ListWithToken(Collections.emptyList(), "2"));
+ responses.add(new ListWithToken(Collections.emptyList(), "3"));
+ responses.add(new ListWithToken(Lists.newArrayList(6, 7, 8, 9, 10), "4"));
+ responses.add(new ListWithToken(Collections.emptyList(), "4"));
+ Function>> func = token -> {
+ ListWithToken result = responses.poll();
+ return new AbstractMap.SimpleEntry<>(result.token, result.list);
+ };
+ ContinuationTokenIterator myIterator = new ContinuationTokenIterator<>(func, null);
+ for (int i = 0; i < 5; i++) {
+ assertTrue(myIterator.hasNext());
+ assertEquals(myIterator.next().intValue(), i + 1);
+ }
+ verify(responses, times(1)).poll();
+ for (int i = 5; i < 10; i++) {
+ assertTrue(myIterator.hasNext());
+ assertEquals(myIterator.next().intValue(), i + 1);
+ }
+ verify(responses, times(4)).poll();
+ assertFalse(myIterator.hasNext());
+ verify(responses, times(5)).poll();
+ }
+
+ @Data
+ static class ListWithToken {
+ private final List list;
+ private final String token;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
new file mode 100644
index 000000000..f8717337c
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/Compatibility.java
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Defines different Compatibility policy options for schema evolution for schemas within a group.
+ * The choice of compatibility policy tells the Schema Registry service whether a schema should be accepted to evolve
+ * into new schema by comparing it with one or more existing versions of the schema.
+ *
+ * {@link Type#AllowAny}: allow any changes to schema without any checks performed by the registry.
+ * {@link Type#DenyAll}: disables any changes to the schema for the group.
+ * {@link Type#Backward}: a new schema can be used to read data written by previous schema.
+ * {@link Type#BackwardTransitive}: a new schema can be used read data written by any of previous schemas.
+ * {@link Type#BackwardTill}: a new schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ * {@link Type#Forward}: previous schema can be used to read data written by new schema.
+ * {@link Type#ForwardTransitive}: all previous schemas can read data written by new schema.
+ * {@link Type#ForwardTill}: All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema.
+ * {@link Type#Full}: both backward and forward compatibility.
+ * {@link Type#FullTransitive}: both backward and forward compatibility with all previous schemas.
+ * {@link Type#BackwardAndForwardTill}: All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema. New schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ */
+@Data
+@Builder
+public class Compatibility implements SchemaValidationRule {
+ /**
+ * Enum that defines the Type of compatibility policy.
+ */
+ private final Type compatibility;
+ /**
+ * Version info to be specified if the compatibility policy choic.e is either {@link Type#backwardTill} or
+ * {@link Type#backwardTillAndForwardTill}.
+ */
+ private final VersionInfo backwardTill;
+ /**
+ * Version info to be specified if the compatibility policy choice is either {@link Type#forwardTill} or
+ * {@link Type#backwardTillAndForwardTill}.
+ */
+ private final VersionInfo forwardTill;
+
+ private Compatibility(Type compatibility) {
+ this(compatibility, null, null);
+ }
+
+ public Compatibility(Type compatibility, VersionInfo backwardTill, VersionInfo forwardTill) {
+ this.compatibility = compatibility;
+ this.backwardTill = backwardTill;
+ this.forwardTill = forwardTill;
+ }
+
+ @Override
+ public String getName() {
+ return Compatibility.class.getSimpleName();
+ }
+
+ public enum Type {
+ AllowAny,
+ DenyAll,
+ Backward,
+ BackwardTill,
+ BackwardTransitive,
+ Forward,
+ ForwardTill,
+ ForwardTransitive,
+ BackwardAndForwardTill,
+ Full,
+ FullTransitive;
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward. Backward policy implies new schema will be validated
+ * to be capable of reading data written using the previous schema.
+ *
+ * @return Compatibility with Type.Backward.
+ */
+ public static Compatibility backward() {
+ return new Compatibility(Type.Backward);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward till. BackwardTill policy implies new schema will be validated
+ * to be capable of reading data written using the all previous schemas till version supplied as input.
+ *
+ * @param backwardTill version till which schemas should be checked for compatibility.
+ * @return Compatibility with Type.BackwardTill version.
+ */
+ public static Compatibility backwardTill(VersionInfo backwardTill) {
+ return new Compatibility(Type.BackwardTill, backwardTill, null);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward transitive. Backward transitive policy implies
+ * new schema will be validated to be capable of reading data written using the all previous schemas versions.
+ *
+ * @return Compatibility with Type.BackwardTransitive.
+ */
+ public static Compatibility backwardTransitive() {
+ return new Compatibility(Type.BackwardTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward. Forward policy implies new schema will be validated
+ * such that data written using new schema can be read using the previous schema.
+ *
+ * @return Compatibility with Type.Forward
+ */
+ public static Compatibility forward() {
+ return new Compatibility(Type.Forward);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward till. Forward policy implies new schema will be validated
+ * such that data written using new schema can be read using the all previous schemas till supplied version.
+ *
+ * @param forwardTill version till which schemas should be checked for compatibility.
+ * @return Compatibility with Type.ForwardTill version.
+ */
+ public static Compatibility forwardTill(VersionInfo forwardTill) {
+ return new Compatibility(Type.ForwardTill, null, forwardTill);
+ }
+
+ /**
+ * Method to create a compatibility policy of type forward transitive.
+ * Forward transitive policy implies new schema will be validated such that data written using new schema
+ * can be read using all previous schemas.
+ *
+ * @return Compatibility with Type.ForwardTransitive.
+ */
+ public static Compatibility forwardTransitive() {
+ return new Compatibility(Type.ForwardTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type full. Full means backward and forward compatibility check with
+ * previous schema version. Which means new schema can be used to read data written with previous schema and vice versa.
+ *
+ * @return Compatibility with Type.Full.
+ */
+ public static Compatibility full() {
+ return new Compatibility(Type.Full);
+ }
+
+ /**
+ * Method to create a compatibility policy of type full transitive.
+ * Full transitive means backward and forward compatibility check with all previous schema version.
+ * This implies new schema can be used to read data written with any of the previous schemas and vice versa.
+ *
+ * @return Compatibility with Type.FullTransitive.
+ */
+ public static Compatibility fullTransitive() {
+ return new Compatibility(Type.FullTransitive);
+ }
+
+ /**
+ * Method to create a compatibility policy of type backward till and forward till. This is a combination of
+ * backward till and forward till policies.
+ * All previous schemas till schema identified by version {@link Compatibility#forwardTill}
+ * can read data written by new schema. New schema can be used to read data written by any of previous schemas till schema
+ * identified by version {@link Compatibility#backwardTill}.
+ *
+ * @param backwardTill version till which backward compatibility is checked for.
+ * @param forwardTill version till which forward compatibility is checked for.
+ * @return Compatibility with Type.FullTransitive.
+ */
+ public static Compatibility backwardTillAndForwardTill(VersionInfo backwardTill, VersionInfo forwardTill) {
+ return new Compatibility(Type.BackwardAndForwardTill, backwardTill, forwardTill);
+ }
+
+ /**
+ * Disable compatibility check and all any schema to be registered. Effectively declares all schemas as compatible.
+ *
+ * @return Compatibility with Type.AllowAny
+ */
+ public static Compatibility allowAny() {
+ return new Compatibility(Type.AllowAny);
+ }
+
+ /**
+ * Compatibility policy that disallows any new schema changes. Effecfively rejects all schemas and declares them incompatible.
+ *
+ * @return Compatibility with Type.DenyAll
+ */
+ public static Compatibility denyAll() {
+ return new Compatibility(Type.DenyAll);
+ }
+
+ public static class CompatibilityBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
new file mode 100644
index 000000000..2d1d625ca
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingId.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * For each group unique set of Encoding Ids are generated for each unique combination of schema version and codec types
+ * registered in the group.
+ * The encoding id will typically be attached to the encoded data in a header to describe how to parse the following data.
+ * The registry service exposes APIs to resolve encoding id to {@link EncodingInfo} objects that include details about the
+ * encoding used.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class EncodingId {
+ /**
+ * A 4byte id that uniquely identifies a {@link VersionInfo} and codecType pair.
+ */
+ private final int id;
+
+ public static class EncodingIdBuilder implements ObjectBuilder {
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
new file mode 100644
index 000000000..f5e396ea2
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/EncodingInfo.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.Data;
+
+/**
+ * Encoding Info describes the details of encoding for each event payload. Each combination of schema version and codec type
+ * is uniquely identified by an {@link EncodingId}.
+ * The registry service exposes APIs to generate or resolve {@link EncodingId} to {@link EncodingInfo}.
+ */
+@Data
+public class EncodingInfo {
+ /**
+ * Version of the schema which is used in encoding the data.
+ */
+ private final VersionInfo versionInfo;
+ /**
+ * Actual schema which is used in encoding the data.
+ */
+ private final SchemaInfo schemaInfo;
+ /**
+ * Codec type which is used in encoding the data.
+ */
+ private final String codecType;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
new file mode 100644
index 000000000..4b9a3d257
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupHistoryRecord.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.Data;
+
+/**
+ * Describes changes to the group and the validation rules {@link GroupHistoryRecord#rules} that were
+ * applied while registering {@link GroupHistoryRecord#schema} and the unique {@link GroupHistoryRecord#version} identifier
+ * that was assigned to it.
+ * It also has {@link GroupHistoryRecord#timestamp} when the schema was added and includes an optional
+ * {@link GroupHistoryRecord#schemaString} which is populated only if serialization format is one of {@link SerializationFormat#Avro}
+ * {@link SerializationFormat#Json} or {@link SerializationFormat#Protobuf}. This string is just to help make the schema human readable.
+ */
+@Data
+public class GroupHistoryRecord {
+ /**
+ * Schema information object for the schema that was added to the group.
+ */
+ private final SchemaInfo schema;
+ /**
+ * Version information object that uniquely identifies the schema in the group.
+ */
+ private final VersionInfo version;
+ /**
+ * Validation rules that were applied at the time when the schema was registered.
+ */
+ private final SchemaValidationRules rules;
+ /**
+ * Service's Time when the schema was registered.
+ */
+ private final long timestamp;
+ /**
+ * A json format string representing the schema. This string will be populated only for serialization formats
+ * that the service can parse.
+ */
+ private final String schemaString;
+}
+
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
new file mode 100644
index 000000000..4002ceebb
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/GroupProperties.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.collect.ImmutableMap;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Different configuration choices for a group.
+ *
+ * {@link GroupProperties#serializationFormat} identifies the serialization format used to describe the schema.
+ * {@link GroupProperties#schemaValidationRules} sets the schema validation policy that needs to be enforced for evolving schemas.
+ * {@link GroupProperties#allowMultipleTypes} that specifies if multiple schemas with distinct {@link SchemaInfo#type}
+ * are allowed to coexist within the group. A schema describes an object and each object type is distinctly identified by
+ * {@link SchemaInfo#type}. Registry service validates new schema with existing schema versions of the same name and versions
+ * it accordingly. Allowing multiple schemas, each versioned independently, allows applications to use schema registry groups
+ * for streaming scenarios like event sourcing, or message bus where different types of events could be written to the same
+ * stream. Similarly, a group with multiple schemas can be used to describe a database catalog with each schema representing
+ * a different table.
+ * The users can register new versions of each distinct type of schema, and the registry will check for compatibility
+ * for each type independently.
+ * {@link GroupProperties#properties} This is general purpose key value string to include any additional user defined information for the group.
+ */
+@Builder
+@Data
+public class GroupProperties {
+ /**
+ * Serialization format allowed for the group.
+ */
+ private final SerializationFormat serializationFormat;
+ /**
+ * Schema validation rules to be applied for the group.
+ */
+ private final SchemaValidationRules schemaValidationRules;
+ /**
+ * Flag to indicate whether multiple types of schemas can be added to the group or not. If set to false, all schemas
+ * added to the group should have the same {@link SchemaInfo#type}.
+ */
+ private final boolean allowMultipleTypes;
+ /**
+ * User defined key value strings for any metadata they want to associate with the group.
+ */
+ private final ImmutableMap properties;
+
+ public GroupProperties(SerializationFormat serializationFormat, SchemaValidationRules schemaValidationRules, boolean allowMultipleTypes) {
+ this(serializationFormat, schemaValidationRules, allowMultipleTypes, ImmutableMap.of());
+ }
+
+ public GroupProperties(SerializationFormat serializationFormat, SchemaValidationRules schemaValidationRules, boolean allowMultipleTypes, ImmutableMap properties) {
+ this.serializationFormat = serializationFormat;
+ this.schemaValidationRules = schemaValidationRules;
+ this.allowMultipleTypes = allowMultipleTypes;
+ this.properties = properties;
+ }
+
+ public static final class GroupPropertiesBuilder {
+ private SchemaValidationRules schemaValidationRules = SchemaValidationRules.of(Compatibility.fullTransitive());
+ private boolean allowMultipleTypes = false;
+ private ImmutableMap properties = ImmutableMap.of();
+
+ public GroupPropertiesBuilder compatibility(Compatibility compatibility) {
+ this.schemaValidationRules = SchemaValidationRules.of(compatibility);
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
new file mode 100644
index 000000000..bc4ed9f62
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaInfo.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Encapsulates properties of a schema.
+ * {@link SchemaInfo#type} object type represented by the schema. This is used to identify the exact object type.
+ * If (ref: {@link GroupProperties#allowMultipleTypes}) is set to true, the group will allow multiple schemas to coexist.
+ * {@link SchemaInfo#serializationFormat} Serialization format.
+ * {@link SchemaInfo#schemaData} Schema as an array of 8-bit unsigned bytes. This is schema-type specific and to be consumed
+ * by schema-type specific parsers.
+ * {@link SchemaInfo#properties} A key value map of strings where user defined metadata can be recorded with schemas.
+ * This is not interpreted by the registry service or client and can be used by applications for sharing any additional
+ * application specific information with the schema.
+ */
+@Data
+@Builder
+public class SchemaInfo {
+ /**
+ * Identifies the object type that is represented by the schema.
+ */
+ private final String type;
+ /**
+ * Serialization format that this schema is intended to be used for.
+ */
+ private final SerializationFormat serializationFormat;
+ /**
+ * Schema as an array of 8-bit unsigned bytes.
+ */
+ private final ByteBuffer schemaData;
+ /**
+ * User defined key value strings that users can use to add any additional metadata to the schema.
+ */
+ private final ImmutableMap properties;
+
+ public SchemaInfo(String type, SerializationFormat serializationFormat, ByteBuffer schemaData, ImmutableMap properties) {
+ Preconditions.checkArgument(type != null);
+ Preconditions.checkArgument(serializationFormat != SerializationFormat.Any);
+ this.type = type;
+ this.serializationFormat = serializationFormat;
+ this.schemaData = schemaData;
+ this.properties = properties;
+ }
+
+ public static class SchemaInfoBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
new file mode 100644
index 000000000..c89670543
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRule.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+/**
+ * Base interface to define all schema validation rules. Schema validation rules are applied whenever new schemas are registered
+ * and only schemas that satisfy validation rules are accepted by the registry into the group.
+ */
+public interface SchemaValidationRule {
+ /**
+ * Name of the rule to identify it with.
+ *
+ * @return name of the rule.
+ */
+ String getName();
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
new file mode 100644
index 000000000..06f77fb09
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaValidationRules.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import com.google.common.base.Preconditions;
+import io.pravega.common.ObjectBuilder;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Schema validation rules that are applied for checking if a schema is valid.
+ * This contains a set of rules {@link SchemaValidationRule}. Currently the only rule that is supported is {@link Compatibility}.
+ * The schema will be compared against one or more existing schemas in the group by checking it for satisfying each of the
+ * rules.
+ */
+@Data
+@Builder
+public class SchemaValidationRules {
+ /**
+ * Map of schema validation rule name to corresponding schema validation rule.
+ */
+ private final Map rules;
+
+ private SchemaValidationRules(Map rules) {
+ this.rules = rules;
+ }
+
+ /**
+ * Method to create a rule for compatibility.
+ *
+ * @param compatibility compatibility policy to be used.
+ * @return A singleton rules map containing the compatibility rule.
+ */
+ public static SchemaValidationRules of(Compatibility compatibility) {
+ return new SchemaValidationRules(Collections.singletonMap(compatibility.getName(), compatibility));
+ }
+
+ /**
+ * Method to create SchemaValidationRules from the list of supplied rules. If multiple same rule are present
+ * in the list then only the latest rule of each type is added to the Rules map.
+ * Currently the only rule supported is {@link Compatibility}.
+ * @param rules List of rules.
+ * @return SchemaValidationRules object.
+ */
+ public static SchemaValidationRules of(List rules) {
+ Preconditions.checkNotNull(rules);
+ Preconditions.checkArgument(rules.stream().allMatch(x -> x instanceof Compatibility), "Only compatibility rule is supported.");
+ return new SchemaValidationRules(rules.stream().collect(Collectors.toMap(SchemaValidationRule::getName, x -> x)));
+ }
+
+ public static class SchemaValidationRulesBuilder implements ObjectBuilder {
+ }
+
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
new file mode 100644
index 000000000..45e730cbf
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SchemaWithVersion.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Object that encapsulates schemaInfo with its associated version.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class SchemaWithVersion {
+ /**
+ * Schema Information object.
+ */
+ private final SchemaInfo schemaInfo;
+ /**
+ * Version information object that identifies the corresponding schema object.
+ */
+ private final VersionInfo versionInfo;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
new file mode 100644
index 000000000..cecb9b257
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/SerializationFormat.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Different types of serialization formats used for serializing data.
+ * Registry supports Avro, Protobuf and Json serialization formats but any custom type could be used with the registry using custom type.
+ *
+ * If a serialization format is not present in the enum it can be specified using {@link SerializationFormat#custom} with {@link SerializationFormat#customTypeName}.
+ * Allowed values of {@link Compatibility} mode with custom type are AllowAny or DenyAll.
+ */
+
+public enum SerializationFormat {
+ Avro,
+ Protobuf,
+ Json,
+ Any,
+ Custom;
+
+ @Getter
+ @Setter(AccessLevel.PRIVATE)
+ private String customTypeName;
+
+ /**
+ * Method to define a custom serialization format with a custom name.
+ * @param customTypeName Custom type name.
+ * @return {@link SerializationFormat#Custom} with supplied custom type name.
+ */
+ public static SerializationFormat custom(String customTypeName) {
+ SerializationFormat type = SerializationFormat.Custom;
+ type.setCustomTypeName(customTypeName);
+ return type;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
new file mode 100644
index 000000000..c281e75e3
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/data/VersionInfo.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.data;
+
+import io.pravega.common.ObjectBuilder;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * Version information object that encapsulates properties that uniquely identify a specific version of a schema within a group.
+ *
+ * {@link VersionInfo#type} is same as {@link SchemaInfo#type} which represents the object type for which the version is computed.
+ * {@link VersionInfo#version} the registry assigned monotonically increasing version number for the schema for specific object type.
+ * Since the version number is per object type, so type and version number forms a unique pair.
+ * {@link VersionInfo#ordinal} Absolute ordinal of the schema for all schemas in the group. This uniquely identifies the
+ * version within a group.
+ */
+@Data
+@Builder
+@AllArgsConstructor
+public class VersionInfo {
+ /**
+ * Object type which is declared in the corresponding {@link SchemaInfo#type} for the schemainfo that is identified
+ * by this version info.
+ */
+ private final String type;
+ /**
+ * A version number that identifies the position of schema among other schemas in the group that share the same 'type'.
+ */
+ private final int version;
+ /**
+ * A position identifier that uniquely identifies the schema within a group and represents the order in which this
+ * schema was included in the group.
+ */
+ private final int ordinal;
+
+ public static class VersionInfoBuilder implements ObjectBuilder {
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
new file mode 100644
index 000000000..310f78ff8
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/AddedTo.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.
+ */
+@ApiModel(description = "Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.")
+
+public class AddedTo {
+ @JsonProperty("groups")
+ private Map groups = new HashMap();
+
+ public AddedTo groups(Map groups) {
+ this.groups = groups;
+ return this;
+ }
+
+ public AddedTo putGroupsItem(String key, VersionInfo groupsItem) {
+ this.groups.put(key, groupsItem);
+ return this;
+ }
+
+ /**
+ * Get groups
+ * @return groups
+ **/
+ @JsonProperty("groups")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public Map getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Map groups) {
+ this.groups = groups;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AddedTo addedTo = (AddedTo) o;
+ return Objects.equals(this.groups, addedTo.groups);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groups);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class AddedTo {\n");
+
+ sb.append(" groups: ").append(toIndentedString(groups)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
new file mode 100644
index 000000000..5f101741a
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CanRead.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for canRead api.
+ */
+@ApiModel(description = "Response object for canRead api.")
+
+public class CanRead {
+ @JsonProperty("compatible")
+ private Boolean compatible = null;
+
+ public CanRead compatible(Boolean compatible) {
+ this.compatible = compatible;
+ return this;
+ }
+
+ /**
+ * Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.
+ * @return compatible
+ **/
+ @JsonProperty("compatible")
+ @ApiModelProperty(required = true, value = "Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.")
+ @NotNull
+ public Boolean isCompatible() {
+ return compatible;
+ }
+
+ public void setCompatible(Boolean compatible) {
+ this.compatible = compatible;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CanRead canRead = (CanRead) o;
+ return Objects.equals(this.compatible, canRead.compatible);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(compatible);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CanRead {\n");
+
+ sb.append(" compatible: ").append(toIndentedString(compatible)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
new file mode 100644
index 000000000..96c10bacc
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CodecTypesList.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for listCodecTypes.
+ */
+@ApiModel(description = "Response object for listCodecTypes.")
+
+public class CodecTypesList {
+ @JsonProperty("codecTypes")
+ private List codecTypes = null;
+
+ public CodecTypesList codecTypes(List codecTypes) {
+ this.codecTypes = codecTypes;
+ return this;
+ }
+
+ public CodecTypesList addCodecTypesItem(String codecTypesItem) {
+ if (this.codecTypes == null) {
+ this.codecTypes = new ArrayList();
+ }
+ this.codecTypes.add(codecTypesItem);
+ return this;
+ }
+
+ /**
+ * List of codecTypes.
+ * @return codecTypes
+ **/
+ @JsonProperty("codecTypes")
+ @ApiModelProperty(value = "List of codecTypes.")
+ public List getCodecTypes() {
+ return codecTypes;
+ }
+
+ public void setCodecTypes(List codecTypes) {
+ this.codecTypes = codecTypes;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CodecTypesList codecTypesList = (CodecTypesList) o;
+ return Objects.equals(this.codecTypes, codecTypesList.codecTypes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(codecTypes);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CodecTypesList {\n");
+
+ sb.append(" codecTypes: ").append(toIndentedString(codecTypes)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
new file mode 100644
index 000000000..459893324
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Compatibility.java
@@ -0,0 +1,216 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Schema Compatibility validation rule.
+ */
+@ApiModel(description = "Schema Compatibility validation rule.")
+
+public class Compatibility {
+ @JsonProperty("name")
+ private String name = null;
+
+ /**
+ * Compatibility policy enum.
+ */
+ public enum PolicyEnum {
+ ALLOWANY("AllowAny"),
+
+ DENYALL("DenyAll"),
+
+ BACKWARD("Backward"),
+
+ FORWARD("Forward"),
+
+ FORWARDTRANSITIVE("ForwardTransitive"),
+
+ BACKWARDTRANSITIVE("BackwardTransitive"),
+
+ BACKWARDTILL("BackwardTill"),
+
+ FORWARDTILL("ForwardTill"),
+
+ BACKWARDANDFORWARDTILL("BackwardAndForwardTill"),
+
+ FULL("Full"),
+
+ FULLTRANSITIVE("FullTransitive");
+
+ private String value;
+
+ PolicyEnum(String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+ @JsonCreator
+ public static PolicyEnum fromValue(String text) {
+ for (PolicyEnum b : PolicyEnum.values()) {
+ if (String.valueOf(b.value).equals(text)) {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ @JsonProperty("policy")
+ private PolicyEnum policy = null;
+
+ @JsonProperty("backwardTill")
+ private VersionInfo backwardTill = null;
+
+ @JsonProperty("forwardTill")
+ private VersionInfo forwardTill = null;
+
+ public Compatibility name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be \"Compatibility\".
+ * @return name
+ **/
+ @JsonProperty("name")
+ @ApiModelProperty(required = true, value = "Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be \"Compatibility\".")
+ @NotNull
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Compatibility policy(PolicyEnum policy) {
+ this.policy = policy;
+ return this;
+ }
+
+ /**
+ * Compatibility policy enum.
+ * @return policy
+ **/
+ @JsonProperty("policy")
+ @ApiModelProperty(required = true, value = "Compatibility policy enum.")
+ @NotNull
+ public PolicyEnum getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(PolicyEnum policy) {
+ this.policy = policy;
+ }
+
+ public Compatibility backwardTill(VersionInfo backwardTill) {
+ this.backwardTill = backwardTill;
+ return this;
+ }
+
+ /**
+ * Version for backward till if policy is BackwardTill or BackwardAndForwardTill.
+ * @return backwardTill
+ **/
+ @JsonProperty("backwardTill")
+ @ApiModelProperty(value = "Version for backward till if policy is BackwardTill or BackwardAndForwardTill.")
+ public VersionInfo getBackwardTill() {
+ return backwardTill;
+ }
+
+ public void setBackwardTill(VersionInfo backwardTill) {
+ this.backwardTill = backwardTill;
+ }
+
+ public Compatibility forwardTill(VersionInfo forwardTill) {
+ this.forwardTill = forwardTill;
+ return this;
+ }
+
+ /**
+ * Version for forward till if policy is ForwardTill or BackwardAndForwardTill.
+ * @return forwardTill
+ **/
+ @JsonProperty("forwardTill")
+ @ApiModelProperty(value = "Version for forward till if policy is ForwardTill or BackwardAndForwardTill.")
+ public VersionInfo getForwardTill() {
+ return forwardTill;
+ }
+
+ public void setForwardTill(VersionInfo forwardTill) {
+ this.forwardTill = forwardTill;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Compatibility compatibility = (Compatibility) o;
+ return Objects.equals(this.name, compatibility.name) &&
+ Objects.equals(this.policy, compatibility.policy) &&
+ Objects.equals(this.backwardTill, compatibility.backwardTill) &&
+ Objects.equals(this.forwardTill, compatibility.forwardTill);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, policy, backwardTill, forwardTill);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class Compatibility {\n");
+
+ sb.append(" name: ").append(toIndentedString(name)).append("\n");
+ sb.append(" policy: ").append(toIndentedString(policy)).append("\n");
+ sb.append(" backwardTill: ").append(toIndentedString(backwardTill)).append("\n");
+ sb.append(" forwardTill: ").append(toIndentedString(forwardTill)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
new file mode 100644
index 000000000..22d2b8b29
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/CreateGroupRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * CreateGroupRequest
+ */
+
+public class CreateGroupRequest {
+ @JsonProperty("groupName")
+ private String groupName = null;
+
+ @JsonProperty("groupProperties")
+ private GroupProperties groupProperties = null;
+
+ public CreateGroupRequest groupName(String groupName) {
+ this.groupName = groupName;
+ return this;
+ }
+
+ /**
+ * Get groupName
+ * @return groupName
+ **/
+ @JsonProperty("groupName")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public void setGroupName(String groupName) {
+ this.groupName = groupName;
+ }
+
+ public CreateGroupRequest groupProperties(GroupProperties groupProperties) {
+ this.groupProperties = groupProperties;
+ return this;
+ }
+
+ /**
+ * Get groupProperties
+ * @return groupProperties
+ **/
+ @JsonProperty("groupProperties")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public GroupProperties getGroupProperties() {
+ return groupProperties;
+ }
+
+ public void setGroupProperties(GroupProperties groupProperties) {
+ this.groupProperties = groupProperties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CreateGroupRequest createGroupRequest = (CreateGroupRequest) o;
+ return Objects.equals(this.groupName, createGroupRequest.groupName) &&
+ Objects.equals(this.groupProperties, createGroupRequest.groupProperties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groupName, groupProperties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class CreateGroupRequest {\n");
+
+ sb.append(" groupName: ").append(toIndentedString(groupName)).append("\n");
+ sb.append(" groupProperties: ").append(toIndentedString(groupProperties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
new file mode 100644
index 000000000..50f95270c
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingId.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Encoding id that uniquely identifies a schema version and codec type pair.
+ */
+@ApiModel(description = "Encoding id that uniquely identifies a schema version and codec type pair.")
+
+public class EncodingId {
+ @JsonProperty("encodingId")
+ private Integer encodingId = null;
+
+ public EncodingId encodingId(Integer encodingId) {
+ this.encodingId = encodingId;
+ return this;
+ }
+
+ /**
+ * encoding id generated by service.
+ * @return encodingId
+ **/
+ @JsonProperty("encodingId")
+ @ApiModelProperty(required = true, value = "encoding id generated by service.")
+ @NotNull
+ public Integer getEncodingId() {
+ return encodingId;
+ }
+
+ public void setEncodingId(Integer encodingId) {
+ this.encodingId = encodingId;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EncodingId encodingId = (EncodingId) o;
+ return Objects.equals(this.encodingId, encodingId.encodingId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(encodingId);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EncodingId {\n");
+
+ sb.append(" encodingId: ").append(toIndentedString(encodingId)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
new file mode 100644
index 000000000..1276ec038
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/EncodingInfo.java
@@ -0,0 +1,144 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Encoding information object that resolves the schema version and codec type used for corresponding encoding id.
+ */
+@ApiModel(description = "Encoding information object that resolves the schema version and codec type used for corresponding encoding id.")
+
+public class EncodingInfo {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("versionInfo")
+ private VersionInfo versionInfo = null;
+
+ @JsonProperty("codecType")
+ private String codecType = null;
+
+ public EncodingInfo schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information object.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information object.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public EncodingInfo versionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ return this;
+ }
+
+ /**
+ * Version information object.
+ * @return versionInfo
+ **/
+ @JsonProperty("versionInfo")
+ @ApiModelProperty(required = true, value = "Version information object.")
+ @NotNull
+ public VersionInfo getVersionInfo() {
+ return versionInfo;
+ }
+
+ public void setVersionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ }
+
+ public EncodingInfo codecType(String codecType) {
+ this.codecType = codecType;
+ return this;
+ }
+
+ /**
+ * Codec type.
+ * @return codecType
+ **/
+ @JsonProperty("codecType")
+ @ApiModelProperty(required = true, value = "Codec type.")
+ @NotNull
+ public String getCodecType() {
+ return codecType;
+ }
+
+ public void setCodecType(String codecType) {
+ this.codecType = codecType;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EncodingInfo encodingInfo = (EncodingInfo) o;
+ return Objects.equals(this.schemaInfo, encodingInfo.schemaInfo) &&
+ Objects.equals(this.versionInfo, encodingInfo.versionInfo) &&
+ Objects.equals(this.codecType, encodingInfo.codecType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, versionInfo, codecType);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EncodingInfo {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" versionInfo: ").append(toIndentedString(versionInfo)).append("\n");
+ sb.append(" codecType: ").append(toIndentedString(codecType)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
new file mode 100644
index 000000000..6376af636
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GetEncodingIdRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * GetEncodingIdRequest
+ */
+
+public class GetEncodingIdRequest {
+ @JsonProperty("versionInfo")
+ private VersionInfo versionInfo = null;
+
+ @JsonProperty("codecType")
+ private String codecType = null;
+
+ public GetEncodingIdRequest versionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ return this;
+ }
+
+ /**
+ * Get versionInfo
+ * @return versionInfo
+ **/
+ @JsonProperty("versionInfo")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public VersionInfo getVersionInfo() {
+ return versionInfo;
+ }
+
+ public void setVersionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ }
+
+ public GetEncodingIdRequest codecType(String codecType) {
+ this.codecType = codecType;
+ return this;
+ }
+
+ /**
+ * Get codecType
+ * @return codecType
+ **/
+ @JsonProperty("codecType")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public String getCodecType() {
+ return codecType;
+ }
+
+ public void setCodecType(String codecType) {
+ this.codecType = codecType;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GetEncodingIdRequest getEncodingIdRequest = (GetEncodingIdRequest) o;
+ return Objects.equals(this.versionInfo, getEncodingIdRequest.versionInfo) &&
+ Objects.equals(this.codecType, getEncodingIdRequest.codecType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(versionInfo, codecType);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GetEncodingIdRequest {\n");
+
+ sb.append(" versionInfo: ").append(toIndentedString(versionInfo)).append("\n");
+ sb.append(" codecType: ").append(toIndentedString(codecType)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
new file mode 100644
index 000000000..cf195ba93
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistory.java
@@ -0,0 +1,101 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * GroupHistory
+ */
+
+public class GroupHistory {
+ @JsonProperty("history")
+ private List history = null;
+
+ public GroupHistory history(List history) {
+ this.history = history;
+ return this;
+ }
+
+ public GroupHistory addHistoryItem(GroupHistoryRecord historyItem) {
+ if (this.history == null) {
+ this.history = new ArrayList();
+ }
+ this.history.add(historyItem);
+ return this;
+ }
+
+ /**
+ * Chronological list of Group History records.
+ * @return history
+ **/
+ @JsonProperty("history")
+ @ApiModelProperty(value = "Chronological list of Group History records.")
+ public List getHistory() {
+ return history;
+ }
+
+ public void setHistory(List history) {
+ this.history = history;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupHistory groupHistory = (GroupHistory) o;
+ return Objects.equals(this.history, groupHistory.history);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(history);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupHistory {\n");
+
+ sb.append(" history: ").append(toIndentedString(history)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
new file mode 100644
index 000000000..6d7dd7476
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupHistoryRecord.java
@@ -0,0 +1,194 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.
+ */
+@ApiModel(description = "Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.")
+
+public class GroupHistoryRecord {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("version")
+ private VersionInfo version = null;
+
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ @JsonProperty("timestamp")
+ private Long timestamp = null;
+
+ @JsonProperty("schemaString")
+ private String schemaString = null;
+
+ public GroupHistoryRecord schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information object.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information object.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public GroupHistoryRecord version(VersionInfo version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Schema version information object.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Schema version information object.")
+ @NotNull
+ public VersionInfo getVersion() {
+ return version;
+ }
+
+ public void setVersion(VersionInfo version) {
+ this.version = version;
+ }
+
+ public GroupHistoryRecord validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Schema validation rules applied.
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(required = true, value = "Schema validation rules applied.")
+ @NotNull
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+ public GroupHistoryRecord timestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ return this;
+ }
+
+ /**
+ * Timestamp when the schema was added.
+ * @return timestamp
+ **/
+ @JsonProperty("timestamp")
+ @ApiModelProperty(required = true, value = "Timestamp when the schema was added.")
+ @NotNull
+ public Long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public GroupHistoryRecord schemaString(String schemaString) {
+ this.schemaString = schemaString;
+ return this;
+ }
+
+ /**
+ * Schema as json string for serialization formats that registry service understands.
+ * @return schemaString
+ **/
+ @JsonProperty("schemaString")
+ @ApiModelProperty(value = "Schema as json string for serialization formats that registry service understands.")
+ public String getSchemaString() {
+ return schemaString;
+ }
+
+ public void setSchemaString(String schemaString) {
+ this.schemaString = schemaString;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupHistoryRecord groupHistoryRecord = (GroupHistoryRecord) o;
+ return Objects.equals(this.schemaInfo, groupHistoryRecord.schemaInfo) &&
+ Objects.equals(this.version, groupHistoryRecord.version) &&
+ Objects.equals(this.validationRules, groupHistoryRecord.validationRules) &&
+ Objects.equals(this.timestamp, groupHistoryRecord.timestamp) &&
+ Objects.equals(this.schemaString, groupHistoryRecord.schemaString);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, version, validationRules, timestamp, schemaString);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupHistoryRecord {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append(" timestamp: ").append(toIndentedString(timestamp)).append("\n");
+ sb.append(" schemaString: ").append(toIndentedString(schemaString)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
new file mode 100644
index 000000000..4bbb60b12
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/GroupProperties.java
@@ -0,0 +1,179 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Metadata for a group.
+ */
+@ApiModel(description = "Metadata for a group.")
+
+public class GroupProperties {
+ @JsonProperty("serializationFormat")
+ private SerializationFormat serializationFormat = null;
+
+ @JsonProperty("schemaValidationRules")
+ private SchemaValidationRules schemaValidationRules = null;
+
+ @JsonProperty("allowMultipleTypes")
+ private Boolean allowMultipleTypes = null;
+
+ @JsonProperty("properties")
+ private Map properties = null;
+
+ public GroupProperties serializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * serialization format for the group.
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "serialization format for the group.")
+ @NotNull
+ public SerializationFormat getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public GroupProperties schemaValidationRules(SchemaValidationRules schemaValidationRules) {
+ this.schemaValidationRules = schemaValidationRules;
+ return this;
+ }
+
+ /**
+ * Validation rules to apply while registering new schema.
+ * @return schemaValidationRules
+ **/
+ @JsonProperty("schemaValidationRules")
+ @ApiModelProperty(required = true, value = "Validation rules to apply while registering new schema.")
+ @NotNull
+ public SchemaValidationRules getSchemaValidationRules() {
+ return schemaValidationRules;
+ }
+
+ public void setSchemaValidationRules(SchemaValidationRules schemaValidationRules) {
+ this.schemaValidationRules = schemaValidationRules;
+ }
+
+ public GroupProperties allowMultipleTypes(Boolean allowMultipleTypes) {
+ this.allowMultipleTypes = allowMultipleTypes;
+ return this;
+ }
+
+ /**
+ * Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.
+ * @return allowMultipleTypes
+ **/
+ @JsonProperty("allowMultipleTypes")
+ @ApiModelProperty(required = true, value = "Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.")
+ @NotNull
+ public Boolean isAllowMultipleTypes() {
+ return allowMultipleTypes;
+ }
+
+ public void setAllowMultipleTypes(Boolean allowMultipleTypes) {
+ this.allowMultipleTypes = allowMultipleTypes;
+ }
+
+ public GroupProperties properties(Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public GroupProperties putPropertiesItem(String key, String propertiesItem) {
+ if (this.properties == null) {
+ this.properties = new HashMap();
+ }
+ this.properties.put(key, propertiesItem);
+ return this;
+ }
+
+ /**
+ * User defined Key value strings.
+ * @return properties
+ **/
+ @JsonProperty("properties")
+ @ApiModelProperty(value = "User defined Key value strings.")
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupProperties groupProperties = (GroupProperties) o;
+ return Objects.equals(this.serializationFormat, groupProperties.serializationFormat) &&
+ Objects.equals(this.schemaValidationRules, groupProperties.schemaValidationRules) &&
+ Objects.equals(this.allowMultipleTypes, groupProperties.allowMultipleTypes) &&
+ Objects.equals(this.properties, groupProperties.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(serializationFormat, schemaValidationRules, allowMultipleTypes, properties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class GroupProperties {\n");
+
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" schemaValidationRules: ").append(toIndentedString(schemaValidationRules)).append("\n");
+ sb.append(" allowMultipleTypes: ").append(toIndentedString(allowMultipleTypes)).append("\n");
+ sb.append(" properties: ").append(toIndentedString(properties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
new file mode 100644
index 000000000..966b6898f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ListGroupsResponse.java
@@ -0,0 +1,128 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Map of Group names to group properties. For partially created groups, the group properties may be null.
+ */
+@ApiModel(description = "Map of Group names to group properties. For partially created groups, the group properties may be null.")
+
+public class ListGroupsResponse {
+ @JsonProperty("groups")
+ private Map groups = null;
+
+ @JsonProperty("continuationToken")
+ private String continuationToken = null;
+
+ public ListGroupsResponse groups(Map groups) {
+ this.groups = groups;
+ return this;
+ }
+
+ public ListGroupsResponse putGroupsItem(String key, GroupProperties groupsItem) {
+ if (this.groups == null) {
+ this.groups = new HashMap();
+ }
+ this.groups.put(key, groupsItem);
+ return this;
+ }
+
+ /**
+ * Get groups
+ * @return groups
+ **/
+ @JsonProperty("groups")
+ @ApiModelProperty(value = "")
+ public Map getGroups() {
+ return groups;
+ }
+
+ public void setGroups(Map groups) {
+ this.groups = groups;
+ }
+
+ public ListGroupsResponse continuationToken(String continuationToken) {
+ this.continuationToken = continuationToken;
+ return this;
+ }
+
+ /**
+ * Continuation token to identify the position of last group in the response.
+ * @return continuationToken
+ **/
+ @JsonProperty("continuationToken")
+ @ApiModelProperty(required = true, value = "Continuation token to identify the position of last group in the response.")
+ @NotNull
+ public String getContinuationToken() {
+ return continuationToken;
+ }
+
+ public void setContinuationToken(String continuationToken) {
+ this.continuationToken = continuationToken;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ListGroupsResponse listGroupsResponse = (ListGroupsResponse) o;
+ return Objects.equals(this.groups, listGroupsResponse.groups) &&
+ Objects.equals(this.continuationToken, listGroupsResponse.continuationToken);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(groups, continuationToken);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class ListGroupsResponse {\n");
+
+ sb.append(" groups: ").append(toIndentedString(groups)).append("\n");
+ sb.append(" continuationToken: ").append(toIndentedString(continuationToken)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
new file mode 100644
index 000000000..2be4282ab
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaInfo.java
@@ -0,0 +1,179 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Arrays;
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Schema information object that encapsulates various properties of a schema.
+ */
+@ApiModel(description = "Schema information object that encapsulates various properties of a schema.")
+
+public class SchemaInfo {
+ @JsonProperty("type")
+ private String type = null;
+
+ @JsonProperty("serializationFormat")
+ private SerializationFormat serializationFormat = null;
+
+ @JsonProperty("schemaData")
+ private byte[] schemaData = null;
+
+ @JsonProperty("properties")
+ private Map properties = null;
+
+ public SchemaInfo type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Name of the schema. This identifies the type of object the schema payload represents.
+ * @return type
+ **/
+ @JsonProperty("type")
+ @ApiModelProperty(required = true, value = "Name of the schema. This identifies the type of object the schema payload represents.")
+ @NotNull
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public SchemaInfo serializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * Type of schema.
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "Type of schema.")
+ @NotNull
+ public SerializationFormat getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormat serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public SchemaInfo schemaData(byte[] schemaData) {
+ this.schemaData = schemaData;
+ return this;
+ }
+
+ /**
+ * Base64 encoded string for binary data for schema.
+ * @return schemaData
+ **/
+ @JsonProperty("schemaData")
+ @ApiModelProperty(required = true, value = "Base64 encoded string for binary data for schema.")
+ @NotNull
+ public byte[] getSchemaData() {
+ return schemaData;
+ }
+
+ public void setSchemaData(byte[] schemaData) {
+ this.schemaData = schemaData;
+ }
+
+ public SchemaInfo properties(Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public SchemaInfo putPropertiesItem(String key, String propertiesItem) {
+ if (this.properties == null) {
+ this.properties = new HashMap();
+ }
+ this.properties.put(key, propertiesItem);
+ return this;
+ }
+
+ /**
+ * User defined key value strings.
+ * @return properties
+ **/
+ @JsonProperty("properties")
+ @ApiModelProperty(value = "User defined key value strings.")
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaInfo schemaInfo = (SchemaInfo) o;
+ return Objects.equals(this.type, schemaInfo.type) &&
+ Objects.equals(this.serializationFormat, schemaInfo.serializationFormat) &&
+ Arrays.equals(this.schemaData, schemaInfo.schemaData) &&
+ Objects.equals(this.properties, schemaInfo.properties);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, serializationFormat, schemaData, properties);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaInfo {\n");
+
+ sb.append(" type: ").append(toIndentedString(type)).append("\n");
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" schemaData: ").append(toIndentedString(schemaData)).append("\n");
+ sb.append(" properties: ").append(toIndentedString(properties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
new file mode 100644
index 000000000..9fb9ee11d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRule.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Schema validation rule base class.
+ */
+@ApiModel(description = "Schema validation rule base class.")
+
+public class SchemaValidationRule {
+ @JsonProperty("rule")
+ private Object rule = null;
+
+ public SchemaValidationRule rule(Object rule) {
+ this.rule = rule;
+ return this;
+ }
+
+ /**
+ * Specific schema validation rule. The only rule we have presently is Compatibility. The \"name\" is used to identify specific Rule type. The only rule supported in this is Compatibility.
+ * @return rule
+ **/
+ @JsonProperty("rule")
+ @ApiModelProperty(required = true, value = "Specific schema validation rule. The only rule we have presently is Compatibility. The \"name\" is used to identify specific Rule type. The only rule supported in this is Compatibility.")
+ @NotNull
+ public Object getRule() {
+ return rule;
+ }
+
+ public void setRule(Object rule) {
+ this.rule = rule;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaValidationRule schemaValidationRule = (SchemaValidationRule) o;
+ return Objects.equals(this.rule, schemaValidationRule.rule);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rule);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaValidationRule {\n");
+
+ sb.append(" rule: ").append(toIndentedString(rule)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
new file mode 100644
index 000000000..0f9d7af0b
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaValidationRules.java
@@ -0,0 +1,103 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRule;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.validation.constraints.*;
+
+/**
+ * Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.
+ */
+@ApiModel(description = "Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.")
+
+public class SchemaValidationRules {
+ @JsonProperty("rules")
+ private Map rules = null;
+
+ public SchemaValidationRules rules(Map rules) {
+ this.rules = rules;
+ return this;
+ }
+
+ public SchemaValidationRules putRulesItem(String key, SchemaValidationRule rulesItem) {
+ if (this.rules == null) {
+ this.rules = new HashMap();
+ }
+ this.rules.put(key, rulesItem);
+ return this;
+ }
+
+ /**
+ * Get rules
+ * @return rules
+ **/
+ @JsonProperty("rules")
+ @ApiModelProperty(value = "")
+ public Map getRules() {
+ return rules;
+ }
+
+ public void setRules(Map rules) {
+ this.rules = rules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaValidationRules schemaValidationRules = (SchemaValidationRules) o;
+ return Objects.equals(this.rules, schemaValidationRules.rules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaValidationRules {\n");
+
+ sb.append(" rules: ").append(toIndentedString(rules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
new file mode 100644
index 000000000..6be73a69d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaVersionsList.java
@@ -0,0 +1,102 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.*;
+
+/**
+ * List of schemas with their versions.
+ */
+@ApiModel(description = "List of schemas with their versions.")
+
+public class SchemaVersionsList {
+ @JsonProperty("schemas")
+ private List schemas = null;
+
+ public SchemaVersionsList schemas(List schemas) {
+ this.schemas = schemas;
+ return this;
+ }
+
+ public SchemaVersionsList addSchemasItem(SchemaWithVersion schemasItem) {
+ if (this.schemas == null) {
+ this.schemas = new ArrayList();
+ }
+ this.schemas.add(schemasItem);
+ return this;
+ }
+
+ /**
+ * List of schemas with their versions.
+ * @return schemas
+ **/
+ @JsonProperty("schemas")
+ @ApiModelProperty(value = "List of schemas with their versions.")
+ public List getSchemas() {
+ return schemas;
+ }
+
+ public void setSchemas(List schemas) {
+ this.schemas = schemas;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaVersionsList schemaVersionsList = (SchemaVersionsList) o;
+ return Objects.equals(this.schemas, schemaVersionsList.schemas);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemas);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaVersionsList {\n");
+
+ sb.append(" schemas: ").append(toIndentedString(schemas)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
new file mode 100644
index 000000000..bc0687fff
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SchemaWithVersion.java
@@ -0,0 +1,119 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.
+ */
+@ApiModel(description = "Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.")
+
+public class SchemaWithVersion {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("version")
+ private VersionInfo version = null;
+
+ public SchemaWithVersion schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Schema information.
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "Schema information.")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public SchemaWithVersion version(VersionInfo version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Version information.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Version information.")
+ @NotNull
+ public VersionInfo getVersion() {
+ return version;
+ }
+
+ public void setVersion(VersionInfo version) {
+ this.version = version;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SchemaWithVersion schemaWithVersion = (SchemaWithVersion) o;
+ return Objects.equals(this.schemaInfo, schemaWithVersion.schemaInfo) &&
+ Objects.equals(this.version, schemaWithVersion.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, version);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SchemaWithVersion {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
new file mode 100644
index 000000000..bc980cbd6
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/SerializationFormat.java
@@ -0,0 +1,154 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.
+ */
+@ApiModel(description = "Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.")
+
+public class SerializationFormat {
+ /**
+ * Gets or Sets serializationFormat
+ */
+ public enum SerializationFormatEnum {
+ AVRO("Avro"),
+
+ PROTOBUF("Protobuf"),
+
+ JSON("Json"),
+
+ ANY("Any"),
+
+ CUSTOM("Custom");
+
+ private String value;
+
+ SerializationFormatEnum(String value) {
+ this.value = value;
+ }
+
+ @Override
+ @JsonValue
+ public String toString() {
+ return String.valueOf(value);
+ }
+
+ @JsonCreator
+ public static SerializationFormatEnum fromValue(String text) {
+ for (SerializationFormatEnum b : SerializationFormatEnum.values()) {
+ if (String.valueOf(b.value).equals(text)) {
+ return b;
+ }
+ }
+ return null;
+ }
+ }
+
+ @JsonProperty("serializationFormat")
+ private SerializationFormatEnum serializationFormat = null;
+
+ @JsonProperty("customTypeName")
+ private String customTypeName = null;
+
+ public SerializationFormat serializationFormat(SerializationFormatEnum serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ return this;
+ }
+
+ /**
+ * Get serializationFormat
+ * @return serializationFormat
+ **/
+ @JsonProperty("serializationFormat")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SerializationFormatEnum getSerializationFormat() {
+ return serializationFormat;
+ }
+
+ public void setSerializationFormat(SerializationFormatEnum serializationFormat) {
+ this.serializationFormat = serializationFormat;
+ }
+
+ public SerializationFormat customTypeName(String customTypeName) {
+ this.customTypeName = customTypeName;
+ return this;
+ }
+
+ /**
+ * Get customTypeName
+ * @return customTypeName
+ **/
+ @JsonProperty("customTypeName")
+ @ApiModelProperty(value = "")
+ public String getCustomTypeName() {
+ return customTypeName;
+ }
+
+ public void setCustomTypeName(String customTypeName) {
+ this.customTypeName = customTypeName;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SerializationFormat serializationFormat = (SerializationFormat) o;
+ return Objects.equals(this.serializationFormat, serializationFormat.serializationFormat) &&
+ Objects.equals(this.customTypeName, serializationFormat.customTypeName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(serializationFormat, customTypeName);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class SerializationFormat {\n");
+
+ sb.append(" serializationFormat: ").append(toIndentedString(serializationFormat)).append("\n");
+ sb.append(" customTypeName: ").append(toIndentedString(customTypeName)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
new file mode 100644
index 000000000..92cdef2d9
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/UpdateValidationRulesRequest.java
@@ -0,0 +1,116 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * UpdateValidationRulesRequest
+ */
+
+public class UpdateValidationRulesRequest {
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ @JsonProperty("previousRules")
+ private SchemaValidationRules previousRules = null;
+
+ public UpdateValidationRulesRequest validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Get validationRules
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+ public UpdateValidationRulesRequest previousRules(SchemaValidationRules previousRules) {
+ this.previousRules = previousRules;
+ return this;
+ }
+
+ /**
+ * Get previousRules
+ * @return previousRules
+ **/
+ @JsonProperty("previousRules")
+ @ApiModelProperty(value = "")
+ public SchemaValidationRules getPreviousRules() {
+ return previousRules;
+ }
+
+ public void setPreviousRules(SchemaValidationRules previousRules) {
+ this.previousRules = previousRules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UpdateValidationRulesRequest updateValidationRulesRequest = (UpdateValidationRulesRequest) o;
+ return Objects.equals(this.validationRules, updateValidationRulesRequest.validationRules) &&
+ Objects.equals(this.previousRules, updateValidationRulesRequest.previousRules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(validationRules, previousRules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class UpdateValidationRulesRequest {\n");
+
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append(" previousRules: ").append(toIndentedString(previousRules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
new file mode 100644
index 000000000..bde7b3f10
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/Valid.java
@@ -0,0 +1,92 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Response object for validateSchema api.
+ */
+@ApiModel(description = "Response object for validateSchema api.")
+
+public class Valid {
+ @JsonProperty("valid")
+ private Boolean valid = null;
+
+ public Valid valid(Boolean valid) {
+ this.valid = valid;
+ return this;
+ }
+
+ /**
+ * Whether given schema is valid with respect to existing group schemas against the configured validation rules.
+ * @return valid
+ **/
+ @JsonProperty("valid")
+ @ApiModelProperty(required = true, value = "Whether given schema is valid with respect to existing group schemas against the configured validation rules.")
+ @NotNull
+ public Boolean isValid() {
+ return valid;
+ }
+
+ public void setValid(Boolean valid) {
+ this.valid = valid;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Valid valid = (Valid) o;
+ return Objects.equals(this.valid, valid.valid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(valid);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class Valid {\n");
+
+ sb.append(" valid: ").append(toIndentedString(valid)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
new file mode 100644
index 000000000..5daa183df
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/ValidateRequest.java
@@ -0,0 +1,117 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * ValidateRequest
+ */
+
+public class ValidateRequest {
+ @JsonProperty("schemaInfo")
+ private SchemaInfo schemaInfo = null;
+
+ @JsonProperty("validationRules")
+ private SchemaValidationRules validationRules = null;
+
+ public ValidateRequest schemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ return this;
+ }
+
+ /**
+ * Get schemaInfo
+ * @return schemaInfo
+ **/
+ @JsonProperty("schemaInfo")
+ @ApiModelProperty(required = true, value = "")
+ @NotNull
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+
+ public void setSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfo = schemaInfo;
+ }
+
+ public ValidateRequest validationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ return this;
+ }
+
+ /**
+ * Get validationRules
+ * @return validationRules
+ **/
+ @JsonProperty("validationRules")
+ @ApiModelProperty(value = "")
+ public SchemaValidationRules getValidationRules() {
+ return validationRules;
+ }
+
+ public void setValidationRules(SchemaValidationRules validationRules) {
+ this.validationRules = validationRules;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ValidateRequest validateRequest = (ValidateRequest) o;
+ return Objects.equals(this.schemaInfo, validateRequest.schemaInfo) &&
+ Objects.equals(this.validationRules, validateRequest.validationRules);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(schemaInfo, validationRules);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class ValidateRequest {\n");
+
+ sb.append(" schemaInfo: ").append(toIndentedString(schemaInfo)).append("\n");
+ sb.append(" validationRules: ").append(toIndentedString(validationRules)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
new file mode 100644
index 000000000..9b4c2603d
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/model/VersionInfo.java
@@ -0,0 +1,142 @@
+/*
+ * Pravega Schema Registry APIs
+ * REST APIs for Pravega Schema Registry.
+ *
+ * OpenAPI spec version: 0.0.1
+ *
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+
+
+package io.pravega.schemaregistry.contract.generated.rest.model;
+
+import java.util.Objects;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import javax.validation.constraints.*;
+
+/**
+ * Version information object.
+ */
+@ApiModel(description = "Version information object.")
+
+public class VersionInfo {
+ @JsonProperty("type")
+ private String type = null;
+
+ @JsonProperty("version")
+ private Integer version = null;
+
+ @JsonProperty("ordinal")
+ private Integer ordinal = null;
+
+ public VersionInfo type(String type) {
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.
+ * @return type
+ **/
+ @JsonProperty("type")
+ @ApiModelProperty(required = true, value = "Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.")
+ @NotNull
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public VersionInfo version(Integer version) {
+ this.version = version;
+ return this;
+ }
+
+ /**
+ * Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.
+ * @return version
+ **/
+ @JsonProperty("version")
+ @ApiModelProperty(required = true, value = "Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.")
+ @NotNull
+ public Integer getVersion() {
+ return version;
+ }
+
+ public void setVersion(Integer version) {
+ this.version = version;
+ }
+
+ public VersionInfo ordinal(Integer ordinal) {
+ this.ordinal = ordinal;
+ return this;
+ }
+
+ /**
+ * Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.
+ * @return ordinal
+ **/
+ @JsonProperty("ordinal")
+ @ApiModelProperty(required = true, value = "Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.")
+ @NotNull
+ public Integer getOrdinal() {
+ return ordinal;
+ }
+
+ public void setOrdinal(Integer ordinal) {
+ this.ordinal = ordinal;
+ }
+
+
+ @Override
+ public boolean equals(java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ VersionInfo versionInfo = (VersionInfo) o;
+ return Objects.equals(this.type, versionInfo.type) &&
+ Objects.equals(this.version, versionInfo.version) &&
+ Objects.equals(this.ordinal, versionInfo.ordinal);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, version, ordinal);
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class VersionInfo {\n");
+
+ sb.append(" type: ").append(toIndentedString(type)).append("\n");
+ sb.append(" version: ").append(toIndentedString(version)).append("\n");
+ sb.append(" ordinal: ").append(toIndentedString(ordinal)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
+
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
new file mode 100644
index 000000000..096b7c1d1
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiException.java
@@ -0,0 +1,10 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class ApiException extends Exception{
+ private int code;
+ public ApiException (int code, String msg) {
+ super(msg);
+ this.code = code;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
new file mode 100644
index 000000000..1ad2cce34
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiOriginFilter.java
@@ -0,0 +1,22 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import java.io.IOException;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+
+
+public class ApiOriginFilter implements javax.servlet.Filter {
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ HttpServletResponse res = (HttpServletResponse) response;
+ res.addHeader("Access-Control-Allow-Origin", "*");
+ res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
+ res.addHeader("Access-Control-Allow-Headers", "Content-Type");
+ chain.doFilter(request, response);
+ }
+
+ public void destroy() {}
+
+ public void init(FilterConfig filterConfig) throws ServletException {}
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
new file mode 100644
index 000000000..47e3f5d76
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/ApiResponseMessage.java
@@ -0,0 +1,69 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import javax.xml.bind.annotation.XmlTransient;
+
+@javax.xml.bind.annotation.XmlRootElement
+
+public class ApiResponseMessage {
+ public static final int ERROR = 1;
+ public static final int WARNING = 2;
+ public static final int INFO = 3;
+ public static final int OK = 4;
+ public static final int TOO_BUSY = 5;
+
+ int code;
+ String type;
+ String message;
+
+ public ApiResponseMessage(){}
+
+ public ApiResponseMessage(int code, String message){
+ this.code = code;
+ switch(code){
+ case ERROR:
+ setType("error");
+ break;
+ case WARNING:
+ setType("warning");
+ break;
+ case INFO:
+ setType("info");
+ break;
+ case OK:
+ setType("ok");
+ break;
+ case TOO_BUSY:
+ setType("too busy");
+ break;
+ default:
+ setType("unknown");
+ break;
+ }
+ this.message = message;
+ }
+
+ @XmlTransient
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
new file mode 100644
index 000000000..deb52b674
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/Bootstrap.java
@@ -0,0 +1,31 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.swagger.jaxrs.config.SwaggerContextService;
+import io.swagger.models.*;
+
+import io.swagger.models.auth.*;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+public class Bootstrap extends HttpServlet {
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ Info info = new Info()
+ .title("Swagger Server")
+ .description("REST APIs for Pravega Schema Registry.")
+ .termsOfService("")
+ .contact(new Contact()
+ .email(""))
+ .license(new License()
+ .name("Apache 2.0")
+ .url("http://www.apache.org/licenses/LICENSE-2.0"));
+
+ ServletContext context = config.getServletContext();
+ Swagger swagger = new Swagger().info(info);
+
+ new SwaggerContextService().withServletConfig(config).updateSwagger(swagger);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
new file mode 100644
index 000000000..16db9f378
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApi.java
@@ -0,0 +1,412 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.GroupsApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.factories.GroupsApiServiceFactory;
+
+import io.swagger.annotations.ApiParam;
+import io.swagger.jaxrs.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.Map;
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.servlet.ServletConfig;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.*;
+import javax.validation.constraints.*;
+
+@Path("/groups")
+
+
+@io.swagger.annotations.Api(description = "the groups API")
+
+public class GroupsApi {
+ private final GroupsApiService delegate;
+
+ public GroupsApi(@Context ServletConfig servletContext) {
+ GroupsApiService delegate = null;
+
+ if (servletContext != null) {
+ String implClass = servletContext.getInitParameter("GroupsApi.implementation");
+ if (implClass != null && !"".equals(implClass.trim())) {
+ try {
+ delegate = (GroupsApiService) Class.forName(implClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ if (delegate == null) {
+ delegate = GroupsApiServiceFactory.getGroupsApi();
+ }
+
+ this.delegate = delegate;
+ }
+
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while registering codectype to a Group", response = Void.class) })
+ public Response addCodecType(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "The codecType" ,required=true) String codecType
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.addCodecType(groupName,codecType,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while adding schema to group", response = Void.class) })
+ public Response addSchema(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Add new schema to group" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.addSchema(groupName,schemaInfo,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class) })
+ public Response canRead(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules." ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.canRead(groupName,schemaInfo,securityContext);
+ }
+ @POST
+
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class) })
+ public Response createGroup(@ApiParam(value = "The Group configuration" ,required=true) CreateGroupRequest createGroupRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.createGroup(createGroupRequest,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}")
+
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class) })
+ public Response deleteGroup(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteGroup(groupName,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class) })
+ public Response deleteSchemaVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type",required=true) @PathParam("type") String type
+,@ApiParam(value = "Version number",required=true) @PathParam("version") Integer version
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteSchemaVersion(groupName,type,version,securityContext);
+ }
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema identified by version from the group.", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class) })
+ public Response deleteSchemaVersionOrinal(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Version ordinal",required=true) @PathParam("versionOrdinal") Integer versionOrdinal
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.deleteSchemaVersionOrinal(groupName,versionOrdinal,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/codecTypes")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class) })
+ public Response getCodecTypesList(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getCodecTypesList(groupName,securityContext);
+ }
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class) })
+ public Response getEncodingId(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Get schema corresponding to the version" ,required=true) GetEncodingIdRequest getEncodingIdRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getEncodingId(groupName,getEncodingIdRequest,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class) })
+ public Response getEncodingInfo(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Encoding id that identifies a unique combination of schema and codec type",required=true) @PathParam("encodingId") Integer encodingId
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getEncodingInfo(groupName,encodingId,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/history")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class) })
+ public Response getGroupHistory(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getGroupHistory(groupName,securityContext);
+ }
+ @GET
+ @Path("/{groupName}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class) })
+ public Response getGroupProperties(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getGroupProperties(groupName,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class) })
+ public Response getSchemaFromVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type",required=true) @PathParam("type") String type
+,@ApiParam(value = "Version number",required=true) @PathParam("version") Integer version
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaFromVersion(groupName,type,version,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class) })
+ public Response getSchemaFromVersionOrdinal(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Version ordinal",required=true) @PathParam("versionOrdinal") Integer versionOrdinal
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaFromVersionOrdinal(groupName,versionOrdinal,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered. It does not automatically register the schema. To add new schema use addSchema", response = VersionInfo.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error fetching version for schema", response = Void.class) })
+ public Response getSchemaVersion(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Get schema corresponding to the version" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaVersion(groupName,schemaInfo,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas/versions")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group", response = SchemaVersionsList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group schema versions", response = Void.class) })
+ public Response getSchemaVersions(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Type of object the schema describes.") @QueryParam("type") String type
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaVersions(groupName,type,securityContext);
+ }
+ @GET
+ @Path("/{groupName}/schemas")
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group's latest schemas", response = Void.class) })
+ public Response getSchemas(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Type of object") @QueryParam("type") String type
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemas(groupName,type,securityContext);
+ }
+ @GET
+
+
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class) })
+ public Response listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken
+,@ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.listGroups(continuationToken,limit,securityContext);
+ }
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({ "application/json" })
+
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class) })
+ public Response updateSchemaValidationRules(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "update group policy" ,required=true) UpdateValidationRulesRequest updateValidationRulesRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.updateSchemaValidationRules(groupName,updateValidationRulesRequest,securityContext);
+ }
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags={ "Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class) })
+ public Response validate(@ApiParam(value = "Group name",required=true) @PathParam("groupName") String groupName
+,@ApiParam(value = "Checks if schema is valid with respect to supplied validation rules" ,required=true) ValidateRequest validateRequest
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.validate(groupName,validateRequest,securityContext);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
new file mode 100644
index 000000000..dd8d9ef40
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/GroupsApiService.java
@@ -0,0 +1,54 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public abstract class GroupsApiService {
+ public abstract Response addCodecType(String groupName,String codecType,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response addSchema(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response canRead(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response createGroup(CreateGroupRequest createGroupRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteGroup(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteSchemaVersion(String groupName,String type,Integer version,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response deleteSchemaVersionOrinal(String groupName,Integer versionOrdinal,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getCodecTypesList(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getEncodingId(String groupName,GetEncodingIdRequest getEncodingIdRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getEncodingInfo(String groupName,Integer encodingId,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getGroupHistory(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getGroupProperties(String groupName,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaFromVersion(String groupName,String type,Integer version,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaFromVersionOrdinal(String groupName,Integer versionOrdinal,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaVersion(String groupName,SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemaVersions(String groupName, String type,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response getSchemas(String groupName, String type,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response listGroups( String continuationToken, Integer limit,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response updateSchemaValidationRules(String groupName,UpdateValidationRulesRequest updateValidationRulesRequest,SecurityContext securityContext) throws NotFoundException;
+ public abstract Response validate(String groupName,ValidateRequest validateRequest,SecurityContext securityContext) throws NotFoundException;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
new file mode 100644
index 000000000..e6179d25f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/JacksonJsonProvider.java
@@ -0,0 +1,18 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.util.Json;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.Provider;
+import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+
+@Provider
+@Produces({MediaType.APPLICATION_JSON})
+public class JacksonJsonProvider extends JacksonJaxbJsonProvider {
+ private static ObjectMapper commonMapper = Json.mapper();
+
+ public JacksonJsonProvider() {
+ super.setMapper(commonMapper);
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
new file mode 100644
index 000000000..e9d99721b
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/NotFoundException.java
@@ -0,0 +1,10 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class NotFoundException extends ApiException {
+ private int code;
+ public NotFoundException (int code, String msg) {
+ super(code, msg);
+ this.code = code;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
new file mode 100644
index 000000000..295bd1d86
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApi.java
@@ -0,0 +1,74 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.SchemasApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.factories.SchemasApiServiceFactory;
+
+import io.swagger.annotations.ApiParam;
+import io.swagger.jaxrs.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.Map;
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import javax.servlet.ServletConfig;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.*;
+import javax.validation.constraints.*;
+
+@Path("/schemas")
+
+
+@io.swagger.annotations.Api(description = "the schemas API")
+
+public class SchemasApi {
+ private final SchemasApiService delegate;
+
+ public SchemasApi(@Context ServletConfig servletContext) {
+ SchemasApiService delegate = null;
+
+ if (servletContext != null) {
+ String implClass = servletContext.getInitParameter("SchemasApi.implementation");
+ if (implClass != null && !"".equals(implClass.trim())) {
+ try {
+ delegate = (SchemasApiService) Class.forName(implClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ if (delegate == null) {
+ delegate = SchemasApiServiceFactory.getSchemasApi();
+ }
+
+ this.delegate = delegate;
+ }
+
+ @POST
+ @Path("/addedTo")
+ @Consumes({ "application/json" })
+ @Produces({ "application/json" })
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags={ "Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class) })
+ public Response getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema" ,required=true) SchemaInfo schemaInfo
+,@Context SecurityContext securityContext)
+ throws NotFoundException {
+ return delegate.getSchemaReferences(schemaInfo,securityContext);
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
new file mode 100644
index 000000000..bcc19dd03
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/SchemasApiService.java
@@ -0,0 +1,22 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public abstract class SchemasApiService {
+ public abstract Response getSchemaReferences(SchemaInfo schemaInfo,SecurityContext securityContext) throws NotFoundException;
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
new file mode 100644
index 000000000..5d19e5e5f
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/StringUtil.java
@@ -0,0 +1,42 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api;
+
+
+public class StringUtil {
+ /**
+ * Check if the given array contains the given value (with case-insensitive comparison).
+ *
+ * @param array The array
+ * @param value The value to search
+ * @return true if the array contains the value
+ */
+ public static boolean containsIgnoreCase(String[] array, String value) {
+ for (String str : array) {
+ if (value == null && str == null) return true;
+ if (value != null && value.equalsIgnoreCase(str)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Join an array of strings with the given separator.
+ *
+ * Note: This might be replaced by utility method from commons-lang or guava someday
+ * if one of those libraries is added as dependency.
+ *
+ *
+ * @param array The array of strings
+ * @param separator The separator
+ * @return the resulting string
+ */
+ public static String join(String[] array, String separator) {
+ int len = array.length;
+ if (len == 0) return "";
+
+ StringBuilder out = new StringBuilder();
+ out.append(array[0]);
+ for (int i = 1; i < len; i++) {
+ out.append(separator).append(array[i]);
+ }
+ return out.toString();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
new file mode 100644
index 000000000..3145181ad
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/GroupsApiServiceFactory.java
@@ -0,0 +1,13 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.factories;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.GroupsApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.impl.GroupsApiServiceImpl;
+
+
+public class GroupsApiServiceFactory {
+ private final static GroupsApiService service = new GroupsApiServiceImpl();
+
+ public static GroupsApiService getGroupsApi() {
+ return service;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
new file mode 100644
index 000000000..8587b6fef
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/factories/SchemasApiServiceFactory.java
@@ -0,0 +1,13 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.factories;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.SchemasApiService;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.impl.SchemasApiServiceImpl;
+
+
+public class SchemasApiServiceFactory {
+ private final static SchemasApiService service = new SchemasApiServiceImpl();
+
+ public static SchemasApiService getSchemasApi() {
+ return service;
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
new file mode 100644
index 000000000..97aea99a9
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/GroupsApiServiceImpl.java
@@ -0,0 +1,134 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.impl;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public class GroupsApiServiceImpl extends GroupsApiService {
+ @Override
+ public Response addCodecType(String groupName, String codecType, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response addSchema(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response canRead(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response createGroup(CreateGroupRequest createGroupRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteGroup(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteSchemaVersion(String groupName, String type, Integer version, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response deleteSchemaVersionOrinal(String groupName, Integer versionOrdinal, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getCodecTypesList(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getEncodingId(String groupName, GetEncodingIdRequest getEncodingIdRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getEncodingInfo(String groupName, Integer encodingId, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getGroupHistory(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getGroupProperties(String groupName, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaFromVersion(String groupName, String type, Integer version, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaFromVersionOrdinal(String groupName, Integer versionOrdinal, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaVersion(String groupName, SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemaVersions(String groupName, String type, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response getSchemas(String groupName, String type, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response listGroups( String continuationToken, Integer limit, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response updateSchemaValidationRules(String groupName, UpdateValidationRulesRequest updateValidationRulesRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+ @Override
+ public Response validate(String groupName, ValidateRequest validateRequest, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
new file mode 100644
index 000000000..565f0f2fb
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest/server/api/impl/SchemasApiServiceImpl.java
@@ -0,0 +1,26 @@
+package io.pravega.schemaregistry.contract.generated.rest.server.api.impl;
+
+import io.pravega.schemaregistry.contract.generated.rest.server.api.*;
+import io.pravega.schemaregistry.contract.generated.rest.model.*;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+
+import java.util.List;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+
+import java.io.InputStream;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.validation.constraints.*;
+
+public class SchemasApiServiceImpl extends SchemasApiService {
+ @Override
+ public Response getSchemaReferences(SchemaInfo schemaInfo, SecurityContext securityContext) throws NotFoundException {
+ // do some magic!
+ return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
+ }
+}
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java b/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
new file mode 100644
index 000000000..fa261ab42
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/transform/ModelHelper.java
@@ -0,0 +1,243 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.transform;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.generated.rest.model.Compatibility;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRule;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import org.apache.commons.lang3.NotImplementedException;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Provides translation (encode/decode) between the Model classes and its REST representation.
+ */
+public class ModelHelper {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ // region decode
+ public static io.pravega.schemaregistry.contract.data.SchemaInfo decode(SchemaInfo schemaInfo) {
+ Preconditions.checkArgument(schemaInfo != null);
+ Preconditions.checkArgument(schemaInfo.getType() != null);
+ Preconditions.checkArgument(schemaInfo.getSerializationFormat() != null);
+ Preconditions.checkArgument(schemaInfo.getProperties() != null);
+ Preconditions.checkArgument(schemaInfo.getSchemaData() != null);
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = decode(schemaInfo.getSerializationFormat());
+ return new io.pravega.schemaregistry.contract.data.SchemaInfo(schemaInfo.getType(),
+ serializationFormat, ByteBuffer.wrap(schemaInfo.getSchemaData()), ImmutableMap.copyOf(schemaInfo.getProperties()));
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SerializationFormat decode(SerializationFormat serializationFormat) {
+ Preconditions.checkArgument(serializationFormat != null);
+ switch (serializationFormat.getSerializationFormat()) {
+ case CUSTOM:
+ Preconditions.checkArgument(serializationFormat.getCustomTypeName() != null);
+ return io.pravega.schemaregistry.contract.data.SerializationFormat.custom(serializationFormat.getCustomTypeName());
+ default:
+ return searchEnum(io.pravega.schemaregistry.contract.data.SerializationFormat.class, serializationFormat.getSerializationFormat().name());
+ }
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SchemaValidationRules decode(SchemaValidationRules rules) {
+ Preconditions.checkArgument(rules != null);
+ Preconditions.checkArgument(rules.getRules() != null);
+ List list = rules.getRules().entrySet().stream().map(rule -> {
+ if (rule.getValue().getRule() instanceof Map) {
+ String name = (String) ((Map) rule.getValue().getRule()).get("name");
+ Preconditions.checkArgument(name.equals(Compatibility.class.getSimpleName()));
+
+ return decode(MAPPER.convertValue(rule.getValue().getRule(), Compatibility.class));
+ } else if (rule.getValue().getRule() instanceof Compatibility) {
+ return decode((Compatibility) rule.getValue().getRule());
+ } else {
+ throw new IllegalArgumentException("Rule not supported");
+ }
+ }).collect(Collectors.toList());
+ return io.pravega.schemaregistry.contract.data.SchemaValidationRules.of(list);
+ }
+
+ public static io.pravega.schemaregistry.contract.data.Compatibility decode(Compatibility compatibility) {
+ Preconditions.checkArgument(compatibility.getName() != null);
+ Preconditions.checkArgument(compatibility.getPolicy() != null);
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.BACKWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getBackwardTill() != null);
+ }
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.FORWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getForwardTill() != null);
+ }
+ if (compatibility.getPolicy().equals(Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL)) {
+ Preconditions.checkArgument(compatibility.getBackwardTill() != null);
+ Preconditions.checkArgument(compatibility.getForwardTill() != null);
+ }
+
+ io.pravega.schemaregistry.contract.data.VersionInfo backwardTill = compatibility.getBackwardTill() == null ? null : decode(compatibility.getBackwardTill());
+ io.pravega.schemaregistry.contract.data.VersionInfo forwardTill = compatibility.getForwardTill() == null ? null : decode(compatibility.getForwardTill());
+
+ return new io.pravega.schemaregistry.contract.data.Compatibility(
+ searchEnum(io.pravega.schemaregistry.contract.data.Compatibility.Type.class, compatibility.getPolicy().name()),
+ backwardTill, forwardTill);
+ }
+
+ public static io.pravega.schemaregistry.contract.data.VersionInfo decode(VersionInfo versionInfo) {
+ Preconditions.checkArgument(versionInfo != null);
+ Preconditions.checkArgument(versionInfo.getType() != null);
+ Preconditions.checkArgument(versionInfo.getVersion() != null);
+ Preconditions.checkArgument(versionInfo.getOrdinal() != null);
+ return new io.pravega.schemaregistry.contract.data.VersionInfo(versionInfo.getType(), versionInfo.getVersion(), versionInfo.getOrdinal());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.EncodingInfo decode(EncodingInfo encodingInfo) {
+ Preconditions.checkArgument(encodingInfo != null);
+ return new io.pravega.schemaregistry.contract.data.EncodingInfo(decode(encodingInfo.getVersionInfo()),
+ decode(encodingInfo.getSchemaInfo()), encodingInfo.getCodecType());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.SchemaWithVersion decode(SchemaWithVersion schemaWithVersion) {
+ Preconditions.checkArgument(schemaWithVersion != null);
+ return new io.pravega.schemaregistry.contract.data.SchemaWithVersion(decode(schemaWithVersion.getSchemaInfo()),
+ decode(schemaWithVersion.getVersion()));
+ }
+
+ public static io.pravega.schemaregistry.contract.data.GroupHistoryRecord decode(GroupHistoryRecord schemaEvolution) {
+ Preconditions.checkArgument(schemaEvolution != null);
+
+ return new io.pravega.schemaregistry.contract.data.GroupHistoryRecord(decode(schemaEvolution.getSchemaInfo()),
+ decode(schemaEvolution.getVersion()), decode(schemaEvolution.getValidationRules()), schemaEvolution.getTimestamp(),
+ schemaEvolution.getSchemaString());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.EncodingId decode(EncodingId encodingId) {
+ Preconditions.checkArgument(encodingId != null);
+ Preconditions.checkArgument(encodingId.getEncodingId() != null);
+
+ return new io.pravega.schemaregistry.contract.data.EncodingId(encodingId.getEncodingId());
+ }
+
+ public static io.pravega.schemaregistry.contract.data.GroupProperties decode(GroupProperties groupProperties) {
+ Preconditions.checkArgument(groupProperties != null);
+ Preconditions.checkArgument(groupProperties.isAllowMultipleTypes() != null);
+
+ return io.pravega.schemaregistry.contract.data.GroupProperties.builder().serializationFormat(decode(groupProperties.getSerializationFormat()))
+ .schemaValidationRules(decode(groupProperties.getSchemaValidationRules())).allowMultipleTypes(groupProperties.isAllowMultipleTypes())
+ .properties(ImmutableMap.copyOf(groupProperties.getProperties())).build();
+ }
+ // endregion
+
+ // region encode
+ public static GroupHistoryRecord encode(io.pravega.schemaregistry.contract.data.GroupHistoryRecord groupHistoryRecord) {
+ return new GroupHistoryRecord().schemaInfo(encode(groupHistoryRecord.getSchema()))
+ .version(encode(groupHistoryRecord.getVersion()))
+ .validationRules(encode(groupHistoryRecord.getRules()))
+ .timestamp(groupHistoryRecord.getTimestamp())
+ .schemaString(groupHistoryRecord.getSchemaString());
+ }
+
+ public static SchemaValidationRules encode(io.pravega.schemaregistry.contract.data.SchemaValidationRules rules) {
+ Map map = rules.getRules().entrySet().stream().collect(Collectors.toMap(rule -> {
+ if (rule.getValue() instanceof io.pravega.schemaregistry.contract.data.Compatibility) {
+ return io.pravega.schemaregistry.contract.generated.rest.model.Compatibility.class.getSimpleName();
+ } else {
+ throw new NotImplementedException("Rule not implemented");
+ }
+ }, rule -> {
+ SchemaValidationRule schemaValidationRule;
+ if (rule.getValue() instanceof io.pravega.schemaregistry.contract.data.Compatibility) {
+ schemaValidationRule = new SchemaValidationRule().rule(encode((io.pravega.schemaregistry.contract.data.Compatibility) rule.getValue()));
+ } else {
+ throw new NotImplementedException("Rule not implemented");
+ }
+ return schemaValidationRule;
+ }));
+ return new SchemaValidationRules().rules(map);
+ }
+
+ public static Compatibility encode(io.pravega.schemaregistry.contract.data.Compatibility compatibility) {
+ Compatibility policy = new io.pravega.schemaregistry.contract.generated.rest.model.Compatibility()
+ .name(compatibility.getName())
+ .policy(searchEnum(Compatibility.PolicyEnum.class, compatibility.getCompatibility().name()));
+ if (compatibility.getBackwardTill() != null) {
+ VersionInfo backwardTill = encode(compatibility.getBackwardTill());
+ policy = policy.backwardTill(backwardTill);
+ }
+ if (compatibility.getForwardTill() != null) {
+ VersionInfo forwardTill = encode(compatibility.getForwardTill());
+ policy = policy.forwardTill(forwardTill);
+ }
+ return policy;
+ }
+
+ public static SchemaWithVersion encode(io.pravega.schemaregistry.contract.data.SchemaWithVersion schemaWithVersion) {
+ return new SchemaWithVersion().schemaInfo(encode(schemaWithVersion.getSchemaInfo()))
+ .version(encode(schemaWithVersion.getVersionInfo()));
+ }
+
+ public static GroupProperties encode(io.pravega.schemaregistry.contract.data.GroupProperties groupProperties) {
+ return new GroupProperties()
+ .serializationFormat(encode(groupProperties.getSerializationFormat()))
+ .properties(groupProperties.getProperties())
+ .allowMultipleTypes(groupProperties.isAllowMultipleTypes())
+ .schemaValidationRules(encode(groupProperties.getSchemaValidationRules()));
+ }
+
+ public static VersionInfo encode(io.pravega.schemaregistry.contract.data.VersionInfo versionInfo) {
+ return new VersionInfo().type(versionInfo.getType()).version(versionInfo.getVersion()).ordinal(versionInfo.getOrdinal());
+ }
+
+ public static SchemaInfo encode(io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo) {
+ return new SchemaInfo().properties(schemaInfo.getProperties()).schemaData(schemaInfo.getSchemaData().array())
+ .type(schemaInfo.getType()).serializationFormat(encode(schemaInfo.getSerializationFormat()));
+ }
+
+ public static SerializationFormat encode(io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat) {
+ if (serializationFormat.equals(io.pravega.schemaregistry.contract.data.SerializationFormat.Custom)) {
+ Preconditions.checkArgument(serializationFormat.getCustomTypeName() != null);
+ SerializationFormat serializationFormatModel = new SerializationFormat().serializationFormat(SerializationFormat.SerializationFormatEnum.CUSTOM);
+ return serializationFormatModel.customTypeName(serializationFormat.getCustomTypeName());
+ } else {
+ return new SerializationFormat().serializationFormat(
+ searchEnum(SerializationFormat.SerializationFormatEnum.class, serializationFormat.name()));
+ }
+ }
+
+ public static EncodingId encode(io.pravega.schemaregistry.contract.data.EncodingId encodingId) {
+ return new EncodingId().encodingId(encodingId.getId());
+ }
+
+ public static EncodingInfo encode(io.pravega.schemaregistry.contract.data.EncodingInfo encodingInfo) {
+ return new EncodingInfo().codecType(encodingInfo.getCodecType())
+ .versionInfo(encode(encodingInfo.getVersionInfo()))
+ .schemaInfo(encode(encodingInfo.getSchemaInfo()));
+ }
+
+ // endregion
+
+ private static > T searchEnum(Class enumeration, String search) {
+ for (T each : enumeration.getEnumConstants()) {
+ if (each.name().compareToIgnoreCase(search) == 0) {
+ return each;
+ }
+ }
+ throw new IllegalArgumentException();
+ }
+}
\ No newline at end of file
diff --git a/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java b/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
new file mode 100644
index 000000000..7ce526198
--- /dev/null
+++ b/contract/src/main/java/io/pravega/schemaregistry/contract/v1/ApiV1.java
@@ -0,0 +1,554 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.v1;
+
+import io.pravega.schemaregistry.contract.generated.rest.model.AddedTo;
+import io.pravega.schemaregistry.contract.generated.rest.model.CanRead;
+import io.pravega.schemaregistry.contract.generated.rest.model.CodecTypesList;
+import io.pravega.schemaregistry.contract.generated.rest.model.CreateGroupRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GetEncodingIdRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupHistory;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.ListGroupsResponse;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaVersionsList;
+import io.pravega.schemaregistry.contract.generated.rest.model.UpdateValidationRulesRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.Valid;
+import io.pravega.schemaregistry.contract.generated.rest.model.ValidateRequest;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import io.pravega.schemaregistry.contract.generated.rest.server.api.NotFoundException;
+import io.swagger.annotations.ApiParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Response;
+
+public class ApiV1 {
+ @Path("/ping")
+ public interface Ping {
+ @GET
+ Response ping();
+ }
+
+ /**
+ * Sync Group apis. Identical to {@link GroupsApiAsync}. All methods in this interface are synchronous and return {@link Response} object.
+ * The purposes of this interface is to be used by proxy-client.
+ */
+ @Path("/v1/groups")
+ @io.swagger.annotations.Api(description = "the groups API")
+ public interface GroupsApi {
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response addCodecType(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "The codec type", required = true) String codecType);
+
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response addSchema(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add new schema to group", required = true) SchemaInfo schemaInfo);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class)})
+ Response canRead(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules.", required = true) SchemaInfo schemaInfo);
+
+ @POST
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ Response createGroup(@ApiParam(value = "The Group configuration", required = true) CreateGroupRequest createGroupRequest);
+
+ @DELETE
+ @Path("/{groupName}")
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class)})
+ Response deleteGroup(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/codecTypes")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class)})
+ Response getCodecTypesList(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class)})
+ Response getEncodingInfo(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Encoding id that identifies a unique combination of schema and codecType", required = true) @PathParam("encodingId") Integer encodingId);
+
+ @GET
+ @Path("/{groupName}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getGroupProperties(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/history")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class)})
+ Response getGroupHistory(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName);
+
+ @GET
+ @Path("/{groupName}/schemas/versions")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemaVersions(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type") @QueryParam("type") String type);
+
+ @GET
+ @Path("/{groupName}/schemas")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemas(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type of object") @QueryParam("type") String type);
+
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class)})
+ Response getEncodingId(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) GetEncodingIdRequest getEncodingIdRequest);
+
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version deleted", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ Response deleteSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version);
+
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ Response getSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version);
+
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ public Response getSchemaFromVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version);
+
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ Response deleteSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered.", response = VersionInfo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ Response getSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) SchemaInfo schemaInfo);
+
+ @GET
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class)})
+ Response listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken,
+ @ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit);
+
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class)})
+ Response updateSchemaValidationRules(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "update group policy", required = true) UpdateValidationRulesRequest updateValidationRulesRequest);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class)})
+ Response validate(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema is valid with respect to supplied validation rules", required = true) ValidateRequest validateRequest);
+ }
+
+ /**
+ * ASync Group apis. Identical to {@link GroupsApi}. All methods in this interface are asynchronous and use
+ * {@link AsyncResponse}. This is used on service side so that all api implementation is asynchronous.
+ */
+ @Path("/v1/groups")
+ @io.swagger.annotations.Api(description = "the groups API")
+ public interface GroupsApiAsync {
+ @POST
+ @Path("/{groupName}/codecTypes")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new codecType to the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added codecType to group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while registering codectype to a Group", response = Void.class)})
+ void addCodecType(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add codec type", required = true) String codecType, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Adds a new schema to the group", response = VersionInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added schema to the group", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Incompatible schema", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 417, message = "Invalid serialization format", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while adding a schema", response = Void.class)})
+ void addSchema(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Add new schema to group", required = true) SchemaInfo schemaInfo, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions/canRead")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.", response = CanRead.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Response to tell whether schema can be used to read existing schemas", response = CanRead.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while checking schema for readability", response = Void.class)})
+ void canRead(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema can be used to read the data in the stream based on compatibility rules.", required = true) SchemaInfo schemaInfo, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Create a new Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 201, message = "Successfully added group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Group with given name already exists", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while creating a Group", response = Void.class)})
+ void createGroup(@ApiParam(value = "The Group configuration", required = true) CreateGroupRequest createGroupRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @DELETE
+ @Path("/{groupName}")
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete a Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Successfully deleted the Group", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting the Group", response = Void.class)})
+ void deleteGroup(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/codecTypes")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get codecTypes for the group.", response = CodecTypesList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found CodecTypes", response = CodecTypesList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching codecTypes registered", response = Void.class)})
+ void getCodecTypesList(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/encodings/{encodingId}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the encoding information corresponding to the encoding id.", response = EncodingInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group or encoding id with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding info corresponding to encoding id", response = Void.class)})
+ void getEncodingInfo(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Encoding id that identifies a unique combination of schema and codecType", required = true) @PathParam("encodingId") Integer encodingId, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the properties of an existing Group", response = GroupProperties.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group properties", response = GroupProperties.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getGroupProperties(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/history")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch the history of schema evolution of a Group", response = GroupHistory.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Group history", response = GroupHistory.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group history", response = Void.class)})
+ void getGroupHistory(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/versions")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get all schema versions for the group.", response = SchemaVersionsList.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Versioned history of schemas registered under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getSchemaVersions(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type") @QueryParam("type") String type,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.", response = SchemaVersionsList.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Latest schemas for all objects identified by SchemaInfo#type under the group", response = SchemaVersionsList.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group's latest schemas", response = Void.class)})
+ void getSchemas(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Type of object") @QueryParam("type") String type,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @PUT
+ @Path("/{groupName}/encodings")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get an encoding id that uniquely identifies a schema version and codec type pair.", response = EncodingId.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Found Encoding", response = EncodingId.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name or version not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 412, message = "Codec type not registered", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while getting encoding id", response = Void.class)})
+ void getEncodingId(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) GetEncodingIdRequest getEncodingIdRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ void getSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @DELETE
+ @Path("/{groupName}/schemas/versions/{versionOrdinal}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ void deleteSchemaFromVersionOrdinal(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "version ordinal", required = true) @PathParam("versionOrdinal") Integer version, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get schema from the version ordinal that uniquely identifies the schema in the group.", response = SchemaInfo.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema corresponding to the version", response = SchemaInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching schema from version", response = Void.class)})
+ void getSchemaFromVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version,
+ @Suspended AsyncResponse asyncResponse);
+
+ @DELETE
+ @Path("/{groupName}/schemas/{type}/versions/{version}")
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Delete schema version from the group.", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 204, message = "Schema corresponding to the version", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while deleting schema from group", response = Void.class)})
+ void deleteSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Schema type from SchemaInfo#type or VersionInfo#type", required = true) @PathParam("type") String type,
+ @ApiParam(value = "Version number", required = true) @PathParam("version") Integer version,
+ @Suspended AsyncResponse asyncResponse);
+
+ @POST
+ @Path("/{groupName}/schemas/versions/find")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Get the version for the schema if it is registered.", response = VersionInfo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = VersionInfo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Group details", response = Void.class)})
+ void getSchemaVersion(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Get schema corresponding to the version", required = true) SchemaInfo schemaInfo,
+ @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @GET
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "List all groups", response = ListGroupsResponse.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "List of all groups", response = ListGroupsResponse.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching the list of Groups", response = Void.class)})
+ void listGroups(@ApiParam(value = "Continuation token") @QueryParam("continuationToken") String continuationToken,
+ @ApiParam(value = "The numbers of items to return") @QueryParam("limit") Integer limit, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @PUT
+ @Path("/{groupName}/rules")
+ @Consumes({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "update schema validation rules of an existing Group", response = Void.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Updated schema validation policy", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 409, message = "Write conflict", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while updating Group's schema validation rules", response = Void.class)})
+ void updateSchemaValidationRules(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "update group policy", required = true) UpdateValidationRulesRequest updateValidationRulesRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+
+ @POST
+ @Path("/{groupName}/schemas/versions/validate")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Checks if given schema is compatible with schemas in the registry for current policy setting.", response = Valid.class, tags = {"Group", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema validation response", response = Valid.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Group with given name not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while trying to validate schema", response = Void.class)})
+ void validate(@ApiParam(value = "Group name", required = true) @PathParam("groupName") String groupName,
+ @ApiParam(value = "Checks if schema is valid with respect to supplied validation rules", required = true) ValidateRequest validateRequest, @Suspended AsyncResponse asyncResponse) throws NotFoundException;
+ }
+
+
+ /**
+ * Sync Schemas apis. Identical to {@link SchemasApiAsync}. All methods in this interface are synchronous and return {@link Response} object.
+ * The purposes of this interface is to be used by proxy-client.
+ */
+ @Path("/v1/schemas")
+ @io.swagger.annotations.Api(description = "the schemas API")
+ public interface SchemasApi {
+ @POST
+ @Path("/addedTo")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class)})
+ Response getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema", required = true) SchemaInfo schemaInfo);
+
+ }
+
+ /**
+ * Sync Schemas apis. Identical to {@link SchemasApi}. All methods in this interface are asynchronous.
+ */
+ @Path("/v1/schemas")
+ @io.swagger.annotations.Api(description = "the schemas API")
+ public interface SchemasApiAsync {
+ @POST
+ @Path("/addedTo")
+ @Consumes({"application/json"})
+ @Produces({"application/json"})
+ @io.swagger.annotations.ApiOperation(value = "", notes = "Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.", response = AddedTo.class, tags = {"Schema", })
+ @io.swagger.annotations.ApiResponses(value = {
+ @io.swagger.annotations.ApiResponse(code = 200, message = "Schema version", response = AddedTo.class),
+ @io.swagger.annotations.ApiResponse(code = 404, message = "Schema not found", response = Void.class),
+ @io.swagger.annotations.ApiResponse(code = 500, message = "Internal server error while fetching Schema references", response = Void.class)})
+ void getSchemaReferences(@ApiParam(value = "Get schema references for the supplied schema", required = true) SchemaInfo schemaInfo,
+ @Suspended AsyncResponse asyncResponse);
+ }
+
+}
diff --git a/contract/src/main/swagger/README.md b/contract/src/main/swagger/README.md
new file mode 100644
index 000000000..bc196acf3
--- /dev/null
+++ b/contract/src/main/swagger/README.md
@@ -0,0 +1,44 @@
+
+Instructions to generate Server REST API stubs
+
+## Delete previously generated directory
+```
+rm -Rf server/src/main/java/io/pravega/schemaregistry/server/io.pravega.rest/generated
+```
+
+## Update schemaregistry.yaml
+All REST API modifications should be done by updating the swagger/schemaregistry.yaml specification file.
+This can be done manually or by using the online editor at http://editor.swagger.io.
+
+## Download Swagger codegen
+Download swagger-codegen-cli from maven - http://repo1.maven.org/maven2/io/swagger/swagger-codegen-cli/2.2.3/swagger-codegen-cli-2.2.3.jar
+
+## Generate the API stubs using Swagger Codegen
+```
+java -jar swagger-codegen-cli.jar generate -i /contract/src/main/swagger/SchemaRegistry.yaml -l jaxrs -c /contract/src/main/swagger/server.config.json -o /contract/
+```
+
+## Remove extra files created by codegen
+All files that get generated outside of the contract/src/main/java/io/pravega/schemaregistry/contract/generated/rest folder should be deleted and not committed to git.
+
+## Update ApiV1.java
+The JAXRS API stubs decorated with swagger annotations are generated in .../contract/io/pravega/schemaregistry/contract/v1/ApiV1.java class.
+Copy these API descriptions into interfaces in .../contract/io.pravega.schemaregistry/contract//v1/ApiV1.java.
+Also make an asynchronour version of APIs in .../contract/io.pravega.schemaregistry/server/rest/v1/ApiV1.java to use only jersey async interfaces.
+
+## Generate documentation
+### Download Swagger2Markup CLI
+https://jcenter.bintray.com/io/github/swagger2markup/swagger2markup-cli/1.3.3/swagger2markup-cli-1.3.3.jar
+
+### Generate and save the markup documentation
+```
+java -Dswagger2markup.markupLanguage=MARKDOWN -Dswagger2markup.generatedExamplesEnabled=true -jar swagger2markup-cli-1.3.3.jar convert -i /contract/src/main/swagger/schemaregistry.yaml -f /documentation/src/docs/io.pravega.rest/restapis
+```
diff --git a/contract/src/main/swagger/SchemaRegistry.yaml b/contract/src/main/swagger/SchemaRegistry.yaml
new file mode 100644
index 000000000..92dba5fd1
--- /dev/null
+++ b/contract/src/main/swagger/SchemaRegistry.yaml
@@ -0,0 +1,867 @@
+#
+# Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Description of the Pravega Schema Registry APIs.
+
+swagger: "2.0"
+info:
+ description: "REST APIs for Pravega Schema Registry."
+ version: "0.0.1"
+ title: Pravega Schema Registry APIs
+ license:
+ name: "Apache 2.0"
+ url: "http://www.apache.org/licenses/LICENSE-2.0"
+basePath: "/v1"
+tags:
+- name: "Group"
+ description: "Group related APIs"
+- name: "Schemas"
+ description: "Schema related APIs"
+schemes:
+ - http
+paths:
+ /groups:
+ get:
+ tags:
+ - "Group"
+ operationId: listGroups
+ description: List all groups
+ produces:
+ - application/json
+ parameters:
+ - in: query
+ name: continuationToken
+ type: string
+ description: Continuation token
+ - in: query
+ name: limit
+ type: integer
+ description: The numbers of items to return
+ required:
+ - limit
+ responses:
+ 200:
+ description: List of all groups
+ schema:
+ $ref: "#/definitions/ListGroupsResponse"
+ 500:
+ description: Internal server error while fetching the list of Groups
+ post:
+ tags:
+ - "Group"
+ operationId: createGroup
+ description: Create a new Group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: CreateGroupRequest
+ description: The Group configuration
+ required: true
+ schema:
+ type: object
+ properties:
+ groupName:
+ type: string
+ groupProperties:
+ $ref: "#/definitions/GroupProperties"
+ required:
+ - groupName
+ - groupProperties
+ responses:
+ 201:
+ description: Successfully added group
+ 409:
+ description: Group with given name already exists
+ 500:
+ description: Internal server error while creating a Group
+ /groups/{groupName}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getGroupProperties
+ description: Fetch the properties of an existing Group
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Group properties
+ schema:
+ $ref: "#/definitions/GroupProperties"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group details
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteGroup
+ description: Delete a Group
+ responses:
+ 204:
+ description: Successfully deleted the Group
+ 500:
+ description: Internal server error while deleting the Group
+ /groups/{groupName}/history:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getGroupHistory
+ description: Fetch the history of schema evolution of a Group
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Group history
+ schema:
+ $ref: "#/definitions/GroupHistory"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group history
+ /groups/{groupName}/rules:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ put:
+ tags:
+ - "Group"
+ operationId: updateSchemaValidationRules
+ description: update schema validation rules of an existing Group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: UpdateValidationRulesRequest
+ description: update group policy
+ required: true
+ schema:
+ type: object
+ properties:
+ validationRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ previousRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ nullable: true
+ required:
+ - validationRules
+ responses:
+ 200:
+ description: Updated schema validation policy
+ 404:
+ description: Group with given name not found
+ 409:
+ description: Write conflict
+ 500:
+ description: Internal server error while updating Group's schema validation rules
+ /groups/{groupName}/schemas:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: query
+ name: type
+ type: string
+ description: Type of object
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemas
+ description: Fetch latest schema versions for all objects identified by SchemaInfo#type under a Group. If query param type is specified then latest schema for the type is returned.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Latest schemas for all objects identified by SchemaInfo#type under the group
+ schema:
+ $ref: "#/definitions/SchemaVersionsList"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group's latest schemas
+ /groups/{groupName}/schemas/versions:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaVersions
+ description: Get all schema versions for the group
+ parameters:
+ - in: query
+ name: type
+ type: string
+ description: Type of object the schema describes.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Versioned history of schemas registered under the group
+ schema:
+ $ref: "#/definitions/SchemaVersionsList"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching Group schema versions
+ post:
+ tags:
+ - "Group"
+ operationId: addSchema
+ description: Adds a new schema to the group
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Add new schema to group
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 201:
+ description: Successfully added schema to the group
+ schema:
+ $ref: "#/definitions/VersionInfo"
+ 404:
+ description: Group not found
+ 409:
+ description: Incompatible schema
+ 417:
+ description: Invalid serialization format
+ 500:
+ description: Internal server error while adding schema to group
+ /groups/{groupName}/schemas/versions/find:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: getSchemaVersion
+ description: Get the version for the schema if it is registered. It does not automatically register the schema. To add new schema use addSchema
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Get schema corresponding to the version
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema version
+ schema:
+ $ref: "#/definitions/VersionInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error fetching version for schema
+ /groups/{groupName}/schemas/versions/{versionOrdinal}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: versionOrdinal
+ description: Version ordinal
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaFromVersionOrdinal
+ description: Get schema from the version ordinal that uniquely identifies the schema in the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema corresponding to the version
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching schema from version
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteSchemaVersionOrinal
+ description: Delete schema identified by version from the group.
+ produces:
+ - application/json
+ responses:
+ 204:
+ description: Schema corresponding to the version
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while deleting schema from group
+ /groups/{groupName}/schemas/{type}/versions/{version}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: type
+ description: Schema type from SchemaInfo#type or VersionInfo#type
+ required: true
+ type: string
+ - in: path
+ name: version
+ description: Version number
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getSchemaFromVersion
+ description: Get schema from the version ordinal that uniquely identifies the schema in the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema corresponding to the version
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while fetching schema from version
+ delete:
+ tags:
+ - "Group"
+ operationId: deleteSchemaVersion
+ description: Delete schema version from the group.
+ produces:
+ - application/json
+ responses:
+ 204:
+ description: Schema corresponding to the version
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while deleting schema from group
+ /groups/{groupName}/schemas/versions/validate:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: validate
+ description: Checks if given schema is compatible with schemas in the registry for current policy setting.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: ValidateRequest
+ description: Checks if schema is valid with respect to supplied validation rules
+ required: true
+ schema:
+ type: object
+ properties:
+ schemaInfo:
+ $ref: "#/definitions/SchemaInfo"
+ validationRules:
+ $ref: "#/definitions/SchemaValidationRules"
+ required:
+ - schemaInfo
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema validation response
+ schema:
+ $ref: "#/definitions/Valid"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while trying to validate schema
+ /groups/{groupName}/schemas/versions/canRead:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ post:
+ tags:
+ - "Group"
+ operationId: canRead
+ description: Checks if given schema can be used for reads subject to compatibility policy in the schema validation rules.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Checks if schema can be used to read the data in the stream based on compatibility rules.
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Response to tell whether schema can be used to read existing schemas
+ schema:
+ $ref: "#/definitions/CanRead"
+ 404:
+ description: Group with given name not found
+ 500:
+ description: Internal server error while checking schema for readability
+ /groups/{groupName}/encodings:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ put:
+ tags:
+ - "Group"
+ operationId: getEncodingId
+ description: Get an encoding id that uniquely identifies a schema version and codec type pair.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: GetEncodingIdRequest
+ description: Get schema corresponding to the version
+ required: true
+ schema:
+ type: object
+ properties:
+ versionInfo:
+ $ref: "#/definitions/VersionInfo"
+ codecType:
+ type: string
+ required:
+ - versionInfo
+ - codecType
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Encoding
+ schema:
+ $ref: "#/definitions/EncodingId"
+ 404:
+ description: Group with given name or version not found
+ 412:
+ description: Codec type not registered
+ 500:
+ description: Internal server error while getting encoding id
+ /groups/{groupName}/encodings/{encodingId}:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ - in: path
+ name: encodingId
+ description: Encoding id that identifies a unique combination of schema and codec type
+ required: true
+ type: integer
+ format: int32
+ get:
+ tags:
+ - "Group"
+ operationId: getEncodingInfo
+ description: Get the encoding information corresponding to the encoding id.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found Encoding
+ schema:
+ $ref: "#/definitions/EncodingInfo"
+ 404:
+ description: Group or encoding id with given name not found
+ 500:
+ description: Internal server error while getting encoding info corresponding to encoding id
+ /groups/{groupName}/codecTypes:
+ parameters:
+ - in: path
+ name: groupName
+ description: Group name
+ required: true
+ type: string
+ get:
+ tags:
+ - "Group"
+ operationId: getCodecTypesList
+ description: Get codecTypes for the group.
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Found CodecTypes
+ schema:
+ $ref: "#/definitions/CodecTypesList"
+ 404:
+ description: Group or encoding id with given name not found
+ 500:
+ description: Internal server error while fetching codecTypes registered
+ post:
+ tags:
+ - "Group"
+ operationId: addCodecType
+ description: Adds a new codecType to the group.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: codecType
+ description: The codecType
+ required: true
+ schema:
+ type: string
+ responses:
+ 201:
+ description: Successfully added codecType to group
+ 404:
+ description: Group not found
+ 500:
+ description: Internal server error while registering codectype to a Group
+ /schemas/addedTo:
+ parameters:
+ post:
+ tags:
+ - "Schema"
+ operationId: getSchemaReferences
+ description: Gets a map of groups to version info where the schema if it is registered. SchemaInfo#properties is ignored while comparing the schema.
+ consumes:
+ - application/json
+ parameters:
+ - in: body
+ name: schemaInfo
+ description: Get schema references for the supplied schema
+ required: true
+ schema:
+ $ref: "#/definitions/SchemaInfo"
+ produces:
+ - application/json
+ responses:
+ 200:
+ description: Schema version
+ schema:
+ $ref: "#/definitions/AddedTo"
+ 404:
+ description: Schema not found
+ 500:
+ description: Internal server error while fetching Schema references
+definitions:
+ ListGroupsResponse:
+ type: object
+ description: Map of Group names to group properties. For partially created groups, the group properties may be null.
+ properties:
+ groups:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/GroupProperties"
+ continuationToken:
+ description: Continuation token to identify the position of last group in the response.
+ type: string
+ required:
+ - continuationToken
+ GroupProperties:
+ type: object
+ description: Metadata for a group.
+ properties:
+ serializationFormat:
+ description: serialization format for the group.
+ $ref: "#/definitions/SerializationFormat"
+ schemaValidationRules:
+ description: Validation rules to apply while registering new schema.
+ $ref: "#/definitions/SchemaValidationRules"
+ allowMultipleTypes:
+ description: Flag to indicate whether to allow multiple schemas representing distinct objects to be registered in the group.
+ type: boolean
+ properties:
+ description: User defined Key value strings.
+ type: object
+ additionalProperties:
+ type: string
+ minLength: 0
+ maxLength: 40
+ required:
+ - serializationFormat
+ - allowMultipleTypes
+ - schemaValidationRules
+ SerializationFormat:
+ type: object
+ description: Serialization format enum that lists different serialization formats supported by the service. To use additional formats, use serializationFormat.Custom and supply customTypeName.
+ properties:
+ serializationFormat:
+ type: string
+ enum:
+ - Avro
+ - Protobuf
+ - Json
+ - Any
+ - Custom
+ customTypeName:
+ type: string
+ required:
+ - serializationFormat
+ SchemaInfo:
+ type: object
+ description: Schema information object that encapsulates various properties of a schema.
+ properties:
+ type:
+ description: Name of the schema. This identifies the type of object the schema payload represents.
+ type: string
+ serializationFormat:
+ description: Type of schema.
+ $ref: "#/definitions/SerializationFormat"
+ schemaData:
+ description: Base64 encoded string for binary data for schema.
+ type: string
+ format: binary
+ properties:
+ description: User defined key value strings.
+ type: object
+ additionalProperties:
+ type: string
+ minLength: 0
+ maxLength: 40
+ required:
+ - type
+ - serializationFormat
+ - schemaData
+ VersionInfo:
+ description: Version information object.
+ type: object
+ properties:
+ type:
+ description: Type of schema for this version. This is same value used in SchemaInfo#Type for the schema this version identifies.
+ type: string
+ version:
+ description: Version number that uniquely identifies the schema version among all schemas in the group that share the same Type.
+ type: integer
+ format: int32
+ ordinal:
+ description: Version ordinal that uniquely identifies the position of the corresponding schema across all schemas in the group.
+ type: integer
+ format: int32
+ required:
+ - type
+ - version
+ - ordinal
+ SchemaWithVersion:
+ type: object
+ description: Object that encapsulates SchemaInfo and its corresponding VersionInfo objects.
+ properties:
+ schemaInfo:
+ description: Schema information.
+ $ref: "#/definitions/SchemaInfo"
+ version:
+ description: Version information.
+ $ref: "#/definitions/VersionInfo"
+ required:
+ - schemaInfo
+ - version
+ SchemaVersionsList:
+ type: object
+ description: List of schemas with their versions.
+ properties:
+ schemas:
+ description: List of schemas with their versions.
+ type: array
+ items:
+ $ref: "#/definitions/SchemaWithVersion"
+ EncodingId:
+ type: object
+ description: Encoding id that uniquely identifies a schema version and codec type pair.
+ properties:
+ encodingId:
+ type: integer
+ format: int32
+ description: encoding id generated by service.
+ required:
+ - encodingId
+ EncodingInfo:
+ type: object
+ description: Encoding information object that resolves the schema version and codec type used for corresponding encoding id.
+ properties:
+ schemaInfo:
+ description: Schema information object.
+ $ref: "#/definitions/SchemaInfo"
+ versionInfo:
+ description: Version information object.
+ $ref: "#/definitions/VersionInfo"
+ codecType:
+ description: Codec type.
+ type: string
+ required:
+ - schemaInfo
+ - versionInfo
+ - codecType
+ Compatibility:
+ type: object
+ description: Schema Compatibility validation rule.
+ required:
+ - name
+ - policy
+ properties:
+ name:
+ type: string
+ description: Name is used to identify the type of SchemaValidationRule. For Compatibility rule the name should be "Compatibility".
+ policy:
+ description: Compatibility policy enum.
+ type: string
+ enum:
+ - AllowAny
+ - DenyAll
+ - Backward
+ - Forward
+ - ForwardTransitive
+ - BackwardTransitive
+ - BackwardTill
+ - ForwardTill
+ - BackwardAndForwardTill
+ - Full
+ - FullTransitive
+ backwardTill:
+ description: Version for backward till if policy is BackwardTill or BackwardAndForwardTill.
+ $ref: "#/definitions/VersionInfo"
+ forwardTill:
+ description: Version for forward till if policy is ForwardTill or BackwardAndForwardTill.
+ $ref: "#/definitions/VersionInfo"
+ SchemaValidationRules:
+ type: object
+ description: Schema validation rules to be applied for new schema addition. Currently only one rule is supported - Compatibility.
+ properties:
+ rules:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/SchemaValidationRule"
+ SchemaValidationRule:
+ type: object
+ description: Schema validation rule base class.
+ required:
+ - rule
+ properties:
+ rule:
+ description: Specific schema validation rule. The only rule we have presently is Compatibility. The "name" is used to identify specific Rule type. The only rule supported in this is Compatibility.
+ oneOf:
+ - $ref: '#/definitions/Compatibility'
+ discriminator:
+ propertyName: name
+ mapping:
+ Compatibility: '#/definitions/Compatibility'
+ CodecTypesList:
+ type: object
+ description: Response object for listCodecTypes.
+ properties:
+ codecTypes:
+ type: array
+ description: List of codecTypes.
+ items:
+ type: string
+ Valid:
+ type: object
+ description: Response object for validateSchema api.
+ properties:
+ valid:
+ description: Whether given schema is valid with respect to existing group schemas against the configured validation rules.
+ type: boolean
+ required:
+ - valid
+ CanRead:
+ type: object
+ description: Response object for canRead api.
+ properties:
+ compatible:
+ description: Whether given schema is compatible and can be used for reads. Compatibility is checked against existing group schemas subject to group's configured compatibility policy.
+ type: boolean
+ required:
+ - compatible
+ GroupHistoryRecord:
+ type: object
+ description: Group History Record that describes each schema evolution - schema information, version generated for the schema, time and rules used for schema validation.
+ properties:
+ schemaInfo:
+ description: Schema information object.
+ $ref: "#/definitions/SchemaInfo"
+ version:
+ description: Schema version information object.
+ $ref: "#/definitions/VersionInfo"
+ validationRules:
+ description: Schema validation rules applied.
+ $ref: "#/definitions/SchemaValidationRules"
+ timestamp:
+ description: Timestamp when the schema was added.
+ type: integer
+ format: int64
+ schemaString:
+ description: Schema as json string for serialization formats that registry service understands.
+ type: string
+ required:
+ - schemaInfo
+ - version
+ - validationRules
+ - timestamp
+ GroupHistory:
+ type: object
+ properties:
+ history:
+ type: array
+ description: Chronological list of Group History records.
+ items:
+ $ref: "#/definitions/GroupHistoryRecord"
+ AddedTo:
+ type: object
+ description: Map of Group names to versionInfos in the group. This is for all the groups where the schema is registered.
+ properties:
+ groups:
+ type: object
+ additionalProperties:
+ $ref: "#/definitions/VersionInfo"
+ required:
+ - groups
diff --git a/contract/src/main/swagger/server.config.json b/contract/src/main/swagger/server.config.json
new file mode 100644
index 000000000..f1ac7594b
--- /dev/null
+++ b/contract/src/main/swagger/server.config.json
@@ -0,0 +1,8 @@
+{
+"sourceFolder" : "src/main/java",
+"implFolder" : "src/main/java",
+"modelPackage" : "io.pravega.schemaregistry.contract.generated.rest.model",
+"apiPackage" : "io.pravega.schemaregistry.contract.generated.rest.server.api",
+"library" : "jersey2",
+"hideGenerationTimestamp" : true
+}
diff --git a/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java b/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
new file mode 100644
index 000000000..c724715db
--- /dev/null
+++ b/contract/src/test/java/io/pravega/schemaregistry/contract/transform/ModelHelperTest.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.contract.transform;
+
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.data.GroupHistoryRecord;
+import io.pravega.schemaregistry.contract.generated.rest.model.Compatibility;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingId;
+import io.pravega.schemaregistry.contract.generated.rest.model.EncodingInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.GroupProperties;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaInfo;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaValidationRules;
+import io.pravega.schemaregistry.contract.generated.rest.model.SchemaWithVersion;
+import io.pravega.schemaregistry.contract.generated.rest.model.SerializationFormat;
+import io.pravega.schemaregistry.contract.generated.rest.model.VersionInfo;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+
+public class ModelHelperTest {
+ @Test
+ public void testDecode() {
+ SerializationFormat type = new SerializationFormat().serializationFormat(SerializationFormat.SerializationFormatEnum.CUSTOM).customTypeName("a");
+ SchemaValidationRules rules = new SchemaValidationRules().rules(Collections.emptyMap());
+ SchemaInfo schema = new SchemaInfo()
+ .type("a").serializationFormat(type).schemaData(new byte[0]).properties(Collections.emptyMap());
+ VersionInfo version = new VersionInfo().type("a").version(1).ordinal(1);
+ Compatibility compatibility = new Compatibility().name(Compatibility.class.getSimpleName())
+ .policy(Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL).backwardTill(version).forwardTill(version);
+ String codecType = "custom";
+
+ // decodes
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = ModelHelper.decode(type);
+ assertEquals(serializationFormat, io.pravega.schemaregistry.contract.data.SerializationFormat.Custom);
+ assertEquals(serializationFormat.getCustomTypeName(), "a");
+
+ io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo = ModelHelper.decode(schema);
+ assertEquals(schemaInfo.getType(), "a");
+ assertEquals(schemaInfo.getSerializationFormat(), serializationFormat);
+ assertNotNull(schemaInfo.getSchemaData());
+ assertNotNull(schemaInfo.getProperties());
+
+ io.pravega.schemaregistry.contract.data.Compatibility compatibilityDecoded = ModelHelper.decode(compatibility);
+ assertEquals(compatibilityDecoded.getCompatibility(), io.pravega.schemaregistry.contract.data.Compatibility.Type.BackwardAndForwardTill);
+
+ io.pravega.schemaregistry.contract.data.SchemaValidationRules rulesDecoded = ModelHelper.decode(rules);
+ assertEquals(rulesDecoded.getRules().size(), 0);
+
+ io.pravega.schemaregistry.contract.data.VersionInfo versionInfo = ModelHelper.decode(version);
+ assertEquals(versionInfo.getType(), version.getType());
+ assertEquals(versionInfo.getVersion(), version.getVersion().intValue());
+
+ io.pravega.schemaregistry.contract.data.EncodingInfo encodingInfo = ModelHelper.decode(new EncodingInfo().schemaInfo(schema).versionInfo(version).codecType(codecType));
+ assertEquals(encodingInfo.getCodecType(), "custom");
+ assertEquals(encodingInfo.getVersionInfo(), versionInfo);
+ assertEquals(encodingInfo.getSchemaInfo(), schemaInfo);
+ io.pravega.schemaregistry.contract.data.SchemaWithVersion schemaWithVersion = ModelHelper.decode(new SchemaWithVersion().schemaInfo(schema).version(version));
+ assertEquals(schemaWithVersion.getVersionInfo(), versionInfo);
+ assertEquals(schemaWithVersion.getSchemaInfo(), schemaInfo);
+
+ io.pravega.schemaregistry.contract.data.EncodingId encodingId = ModelHelper.decode(new EncodingId().encodingId(1));
+ assertEquals(encodingId.getId(), 1);
+ }
+
+ @Test
+ public void testEncode() {
+ io.pravega.schemaregistry.contract.data.SerializationFormat serializationFormat = io.pravega.schemaregistry.contract.data.SerializationFormat.custom("custom");
+ io.pravega.schemaregistry.contract.data.SchemaInfo schemaInfo = new io.pravega.schemaregistry.contract.data.SchemaInfo(
+ "name", serializationFormat, ByteBuffer.wrap(new byte[0]), ImmutableMap.of());
+ io.pravega.schemaregistry.contract.data.VersionInfo versionInfo = new io.pravega.schemaregistry.contract.data.VersionInfo("a", 0, 1);
+ io.pravega.schemaregistry.contract.data.Compatibility rule = io.pravega.schemaregistry.contract.data.Compatibility.backwardTillAndForwardTill(
+ new io.pravega.schemaregistry.contract.data.VersionInfo("a", 0, 0),
+ new io.pravega.schemaregistry.contract.data.VersionInfo("a", 1, 1));
+ io.pravega.schemaregistry.contract.data.SchemaValidationRules schemaValidationRules = io.pravega.schemaregistry.contract.data.SchemaValidationRules.of(rule);
+ io.pravega.schemaregistry.contract.data.GroupProperties prop = io.pravega.schemaregistry.contract.data.GroupProperties
+ .builder().serializationFormat(serializationFormat).schemaValidationRules(schemaValidationRules)
+ .allowMultipleTypes(true).properties(ImmutableMap.of()).build();
+ String codecType = "codecType";
+
+ // encode test
+ VersionInfo version = ModelHelper.encode(versionInfo);
+ assertEquals(version.getVersion().intValue(), versionInfo.getVersion());
+ assertEquals(version.getType(), versionInfo.getType());
+
+ SerializationFormat type = ModelHelper.encode(serializationFormat);
+ assertEquals(type.getSerializationFormat(), SerializationFormat.SerializationFormatEnum.CUSTOM);
+
+ SchemaInfo schema = ModelHelper.encode(schemaInfo);
+ assertEquals(schema.getType(), schemaInfo.getType());
+ assertEquals(schema.getProperties(), schemaInfo.getProperties());
+ assertTrue(Arrays.equals(schema.getSchemaData(), schemaInfo.getSchemaData().array()));
+ assertEquals(schema.getSerializationFormat(), type);
+
+ EncodingId encodingId = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.EncodingId(0));
+ assertEquals(encodingId.getEncodingId().intValue(), 0);
+
+ EncodingInfo encodingInfo = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.EncodingInfo(versionInfo, schemaInfo, codecType));
+ assertEquals(encodingInfo.getCodecType(), codecType);
+ assertEquals(encodingInfo.getVersionInfo(), version);
+ assertEquals(encodingInfo.getSchemaInfo(), schema);
+
+ SchemaValidationRules rules = ModelHelper.encode(schemaValidationRules);
+ assertEquals(rules.getRules().size(), 1);
+
+ io.pravega.schemaregistry.contract.generated.rest.model.GroupHistoryRecord schemaEvolution = ModelHelper.encode(new GroupHistoryRecord(
+ schemaInfo, versionInfo, schemaValidationRules, 100L, ""));
+ assertEquals(schemaEvolution.getSchemaInfo(), schema);
+ assertEquals(schemaEvolution.getValidationRules(), rules);
+ assertEquals(schemaEvolution.getVersion(), version);
+ assertEquals(schemaEvolution.getTimestamp().longValue(), 100L);
+ assertEquals(schemaEvolution.getSchemaString(), "");
+
+ Compatibility compatibility = ModelHelper.encode(rule);
+ assertEquals(compatibility.getPolicy(), Compatibility.PolicyEnum.BACKWARDANDFORWARDTILL);
+
+ SchemaWithVersion schemaWithVersion = ModelHelper.encode(new io.pravega.schemaregistry.contract.data.SchemaWithVersion(schemaInfo, versionInfo));
+ assertEquals(schemaWithVersion.getSchemaInfo(), schema);
+ assertEquals(schemaWithVersion.getVersion(), version);
+
+ GroupProperties groupProperties = ModelHelper.encode(prop);
+ assertEquals(groupProperties.getSerializationFormat(), type);
+ assertEquals(groupProperties.getSchemaValidationRules(), rules);
+ assertEquals(groupProperties.isAllowMultipleTypes(), prop.isAllowMultipleTypes());
+ assertEquals(groupProperties.getProperties(), prop.getProperties());
+ }
+
+}
diff --git a/settings.gradle b/settings.gradle
index 600f3080a..dc820fbbc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -10,3 +10,7 @@
*/
rootProject.name = 'schema-registry'
+include 'client',
+ 'common',
+ 'contract'
+
\ No newline at end of file
From a0876cc5a185a7a4a93f9df84647b0654a7afb47 Mon Sep 17 00:00:00 2001
From: Shivesh Ranjan
Date: Sun, 7 Jun 2020 19:47:10 -0700
Subject: [PATCH 03/70] serializers copying over
Signed-off-by: Shivesh Ranjan
---
build.gradle | 27 +
.../schemaregistry/GroupIdGenerator.java | 45 +
.../schemaregistry/cache/EncodingCache.java | 65 +
.../pravega/schemaregistry/codec/Codec.java | 23 +
.../schemaregistry/codec/CodecFactory.java | 129 +
.../schemaregistry/schemas/AvroSchema.java | 107 +
.../schemaregistry/schemas/JSONSchema.java | 123 +
.../schemas/ProtobufSchema.java | 122 +
.../schemas/SchemaContainer.java | 21 +
.../AbstractPravegaDeserializer.java | 133 +
.../AbstractPravegaSerializer.java | 123 +
.../serializers/AvroDeserlizer.java | 60 +
.../serializers/AvroGenericDeserlizer.java | 56 +
.../serializers/AvroSerializer.java | 62 +
.../serializers/JSonGenericObject.java | 21 +
.../serializers/JsonDeserlizer.java | 48 +
.../serializers/JsonGenericDeserlizer.java | 52 +
.../serializers/JsonSerializer.java | 37 +
.../MultipleFormatGenericDeserializer.java | 37 +
.../MultipleFormatJsonStringDeserializer.java | 58 +
.../MultiplexedAndGenericDeserializer.java | 44 +
.../serializers/MultiplexedDeserializer.java | 36 +
.../serializers/MultiplexedSerializer.java | 36 +
.../serializers/PravegaDeserializer.java | 18 +
.../serializers/PravegaSerializer.java | 18 +
.../serializers/ProtobufDeserlizer.java | 37 +
.../ProtobufGenericDeserlizer.java | 77 +
.../serializers/ProtobufSerializer.java | 32 +
.../serializers/SerializerConfig.java | 182 ++
.../serializers/SerializerFactory.java | 675 ++++
.../pravega/schemaregistry/GroupIdTest.java | 29 +
.../schemaregistry/cache/CacheTest.java | 41 +
.../schemaregistry/codec/CodecTest.java | 47 +
.../schemaregistry/schemas/TestSchemas.java | 103 +
.../serializers/SerializerTest.java | 388 +++
.../schemaregistry/testobjs/Address.java | 22 +
.../schemaregistry/testobjs/DerivedUser1.java | 28 +
.../schemaregistry/testobjs/DerivedUser2.java | 28 +
.../testobjs/SchemaDefinitions.java | 61 +
.../pravega/schemaregistry/testobjs/User.java | 28 +
.../testobjs/generated/ProtobufTest.java | 2836 +++++++++++++++++
.../testobjs/generated/Test1.java | 389 +++
.../testobjs/generated/Test2.java | 469 +++
.../testobjs/generated/Test3.java | 549 ++++
.../src/test/resources/avro/avroTest1.avsc | 9 +
.../src/test/resources/avro/avroTest2.avsc | 10 +
.../src/test/resources/avro/avroTest3.avsc | 11 +
.../src/test/resources/proto/protobufTest.pb | Bin 0 -> 498 bytes
.../test/resources/proto/protobufTest.proto | 28 +
settings.gradle | 5 +
50 files changed, 7585 insertions(+)
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/GroupIdGenerator.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/cache/EncodingCache.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/codec/Codec.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/codec/CodecFactory.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/schemas/AvroSchema.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/schemas/JSONSchema.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/schemas/ProtobufSchema.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/schemas/SchemaContainer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/AbstractPravegaDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/AbstractPravegaSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/AvroDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/AvroGenericDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/AvroSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/JSonGenericObject.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/JsonDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/JsonGenericDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/JsonSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/MultipleFormatGenericDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/MultipleFormatJsonStringDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/MultiplexedAndGenericDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/MultiplexedDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/MultiplexedSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/PravegaDeserializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/PravegaSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/ProtobufDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/ProtobufGenericDeserlizer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/ProtobufSerializer.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/SerializerConfig.java
create mode 100644 serializers/src/main/java/io/pravega/schemaregistry/serializers/SerializerFactory.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/GroupIdTest.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/cache/CacheTest.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/codec/CodecTest.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/schemas/TestSchemas.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/serializers/SerializerTest.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/Address.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/DerivedUser1.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/DerivedUser2.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/SchemaDefinitions.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/User.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/generated/ProtobufTest.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/generated/Test1.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/generated/Test2.java
create mode 100644 serializers/src/test/java/io/pravega/schemaregistry/testobjs/generated/Test3.java
create mode 100644 serializers/src/test/resources/avro/avroTest1.avsc
create mode 100644 serializers/src/test/resources/avro/avroTest2.avsc
create mode 100644 serializers/src/test/resources/avro/avroTest3.avsc
create mode 100644 serializers/src/test/resources/proto/protobufTest.pb
create mode 100644 serializers/src/test/resources/proto/protobufTest.proto
diff --git a/build.gradle b/build.gradle
index 52125793d..f7b2f6d7f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -196,3 +196,30 @@ def getProjectVersion() {
}
return ver
}
+
+project('serializers') {
+ dependencies {
+ compile project(':common')
+ compile project(':client')
+ compile group: 'org.apache.avro', name: 'avro', version: avroVersion
+ compile group: 'org.apache.avro', name: 'avro-protobuf', version: avroProtobufVersion
+ compile group: 'com.google.protobuf', name: 'protobuf-java', version: protobufProtocVersion
+ compile group: 'com.google.protobuf', name:'protobuf-gradle-plugin', version: protobufGradlePlugin
+ compile group: 'com.google.protobuf', name: 'protobuf-java-util', version: protobufUtilVersion
+ compile group: 'io.pravega', name: 'pravega-client', version: pravegaVersion
+ compile group: 'org.xerial.snappy', name: 'snappy-java', version: snappyVersion
+ compile group: 'com.fasterxml.jackson.module', name: 'jackson-module-jsonSchema', version: jacksonVersion
+ testCompile group: 'org.slf4j', name: 'log4j-over-slf4j', version: slf4jApiVersion
+ testCompile group: 'ch.qos.logback', name: 'logback-classic', version: qosLogbackVersion
+ testCompile group: 'io.pravega', name: 'pravega-test-testcommon', version: pravegaVersion
+ }
+
+ javadoc {
+ title = "Serializers"
+ dependsOn delombok
+ source = delombok.outputDir
+ failOnError = false
+ exclude "**/impl/**";
+ options.addBooleanOption("Xdoclint:all,-reference", true)
+ }
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/GroupIdGenerator.java b/serializers/src/main/java/io/pravega/schemaregistry/GroupIdGenerator.java
new file mode 100644
index 000000000..36a1488fb
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/GroupIdGenerator.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry;
+
+import com.google.common.base.Preconditions;
+import lombok.SneakyThrows;
+
+/**
+ * Defines strategies for generating groupId for stream.
+ * Currently there is only one naming strategy that uses streams fully qualified scoped stream name and encodes it using
+ * URL encoder.
+ */
+public class GroupIdGenerator {
+ private GroupIdGenerator() {
+ }
+
+ @SneakyThrows
+ public static String getGroupId(Type type, String... args) {
+ switch (type) {
+ case QualifiedStreamName:
+ Preconditions.checkNotNull(args);
+ Preconditions.checkArgument(args.length == 2);
+ StringBuilder qualifiedNameBuilder = new StringBuilder();
+ qualifiedNameBuilder.append("pravega://");
+ for (String arg : args) {
+ qualifiedNameBuilder.append(arg);
+ qualifiedNameBuilder.append("/");
+ }
+ return qualifiedNameBuilder.toString();
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public enum Type {
+ QualifiedStreamName,
+ }
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/cache/EncodingCache.java b/serializers/src/main/java/io/pravega/schemaregistry/cache/EncodingCache.java
new file mode 100644
index 000000000..b1a336a5f
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/cache/EncodingCache.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.cache;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import io.pravega.schemaregistry.client.SchemaRegistryClient;
+import io.pravega.schemaregistry.contract.data.EncodingId;
+import io.pravega.schemaregistry.contract.data.EncodingInfo;
+import lombok.Data;
+import lombok.SneakyThrows;
+import lombok.Synchronized;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Local cache for storing schemas that are retrieved from the registry service.
+ */
+public class EncodingCache {
+ private static final Map GROUP_CACHE_MAP = new HashMap<>();
+
+ private final LoadingCache encodingCache;
+
+ private EncodingCache(String groupId, SchemaRegistryClient schemaRegistryClient) {
+ encodingCache = CacheBuilder.newBuilder().build(new CacheLoader() {
+ @Override
+ public EncodingInfo load(EncodingId key) {
+ return schemaRegistryClient.getEncodingInfo(groupId, key);
+ }
+ });
+ }
+
+ @SneakyThrows(ExecutionException.class)
+ public EncodingInfo getGroupEncodingInfo(EncodingId encodingId) {
+ return encodingCache.get(encodingId);
+ }
+
+ @Synchronized
+ public static EncodingCache getEncodingCacheForGroup(String groupId, SchemaRegistryClient schemaRegistryClient) {
+ Key key = new Key(schemaRegistryClient, groupId);
+ if (GROUP_CACHE_MAP.containsKey(key)) {
+ return GROUP_CACHE_MAP.get(key);
+ } else {
+ EncodingCache value = new EncodingCache(groupId, schemaRegistryClient);
+ GROUP_CACHE_MAP.put(key, value);
+ return value;
+ }
+ }
+
+ @Data
+ private static class Key {
+ private final SchemaRegistryClient client;
+ private final String groupId;
+ }
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/codec/Codec.java b/serializers/src/main/java/io/pravega/schemaregistry/codec/Codec.java
new file mode 100644
index 000000000..4cfaf7052
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/codec/Codec.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.codec;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Codec interface that defines methods to encode and decoder data for a given codec type.
+ */
+public interface Codec {
+ String getCodecType();
+
+ ByteBuffer encode(ByteBuffer data);
+
+ ByteBuffer decode(ByteBuffer data);
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/codec/CodecFactory.java b/serializers/src/main/java/io/pravega/schemaregistry/codec/CodecFactory.java
new file mode 100644
index 000000000..d3d74b572
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/codec/CodecFactory.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.codec;
+
+import lombok.SneakyThrows;
+import org.xerial.snappy.Snappy;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Factory class for creating codecs for codec types .
+ */
+public class CodecFactory {
+ public static final String NONE = "";
+ public static final String MIME_GZIP = "application/x-gzip";
+ public static final String MIME_SNAPPY = "application/x-snappy-framed";
+
+ private static final Noop NOOP = new Noop();
+ private static final GZipCodec GZIP_COMPRESSOR = new GZipCodec();
+ private static final SnappyCodec SNAPPY_COMPRESSOR = new SnappyCodec();
+
+ public static Codec none() {
+ return NOOP;
+ }
+
+ public static Codec gzip() {
+ return GZIP_COMPRESSOR;
+ }
+
+ public static Codec snappy() {
+ return SNAPPY_COMPRESSOR;
+ }
+
+ private static class Noop implements Codec {
+ @Override
+ public String getCodecType() {
+ return NONE;
+ }
+
+ @Override
+ public ByteBuffer encode(ByteBuffer data) {
+ return data;
+ }
+
+ @Override
+ public ByteBuffer decode(ByteBuffer data) {
+ return data;
+ }
+ }
+
+ private static class GZipCodec implements Codec {
+ @Override
+ public String getCodecType() {
+ return MIME_GZIP;
+ }
+
+ @SneakyThrows(IOException.class)
+ @Override
+ public ByteBuffer encode(ByteBuffer data) {
+ byte[] array = new byte[data.remaining()];
+ data.get(array);
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(array.length);
+ GZIPOutputStream gzipOS = new GZIPOutputStream(bos);
+ gzipOS.write(array);
+ gzipOS.close();
+ byte[] compressed = bos.toByteArray();
+ return ByteBuffer.wrap(compressed);
+ }
+
+ @SneakyThrows(IOException.class)
+ @Override
+ public ByteBuffer decode(ByteBuffer data) {
+ byte[] array = new byte[data.remaining()];
+ data.get(array);
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(array);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ GZIPInputStream gzipIS = new GZIPInputStream(bis);
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = gzipIS.read(buffer)) != -1) {
+ bos.write(buffer, 0, len);
+ }
+ byte[] uncompressed = bos.toByteArray();
+ return ByteBuffer.wrap(uncompressed);
+ }
+ }
+
+ private static class SnappyCodec implements Codec {
+ @Override
+ public String getCodecType() {
+ return MIME_SNAPPY;
+ }
+
+ @SneakyThrows(IOException.class)
+ @Override
+ public ByteBuffer encode(ByteBuffer data) {
+ byte[] array = new byte[data.remaining()];
+ data.get(array);
+
+ byte[] compressed = Snappy.compress(array);
+ return ByteBuffer.wrap(compressed);
+ }
+
+ @SneakyThrows(IOException.class)
+ @Override
+ public ByteBuffer decode(ByteBuffer data) {
+ byte[] array = new byte[data.remaining()];
+ data.get(array);
+
+ byte[] uncompressed = Snappy.uncompress(array);
+ return ByteBuffer.wrap(uncompressed);
+ }
+ }
+
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/schemas/AvroSchema.java b/serializers/src/main/java/io/pravega/schemaregistry/schemas/AvroSchema.java
new file mode 100644
index 000000000..5cb4e7ae1
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/schemas/AvroSchema.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.schemas;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SerializationFormat;
+import lombok.Getter;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.reflect.ReflectData;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificRecordBase;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Container class for Avro Schema.
+ *
+ * @param Type of element.
+ */
+public class AvroSchema implements SchemaContainer {
+ @Getter
+ private final Schema schema;
+ private final SchemaInfo schemaInfo;
+
+ private AvroSchema(Schema schema) {
+ this.schema = schema;
+ this.schemaInfo = new SchemaInfo(schema.getFullName(),
+ SerializationFormat.Avro, getSchemaBytes(), ImmutableMap.of());
+ }
+
+ /**
+ * Method to create a typed AvroSchema for the given class. It extracts the avro schema from the class.
+ * For Avro generated classes, the schema is retrieved from the class.
+ * For POJOs the schema is extracted using avro's {@link ReflectData}.
+ *
+ * @param tClass Class whose object's schema is used.
+ * @param Type of the Java class.
+ * @return {@link AvroSchema} with generic type T that extracts and captures the avro schema.
+ */
+ public static AvroSchema of(Class tClass) {
+ Schema schema;
+ if (SpecificRecordBase.class.isAssignableFrom(tClass)) {
+ schema = SpecificData.get().getSchema(tClass);
+ } else {
+ schema = ReflectData.get().getSchema(tClass);
+ }
+ return new AvroSchema<>(schema);
+ }
+
+ /**
+ * Method to create a typed AvroSchema of type {@link GenericRecord} from the given schema.
+ *
+ * @param schema Schema to use.
+ * @return Returns an AvroSchema with {@link GenericRecord} type.
+ */
+ public static AvroSchema of(Schema schema) {
+ return new AvroSchema<>(schema);
+ }
+
+ /**
+ * It is same as {@link #of(Class)} except that it generates an AvroSchema typed as {@link SpecificRecordBase}.
+ *
+ * This is useful for supplying a map of Avro schemas for multiplexed serializers and deserializers.
+ *
+ * @param tClass Class whose schema should be used.
+ * @param Type of class whose schema is to be used.
+ * @return Returns an AvroSchema with {@link SpecificRecordBase} type.
+ */
+ public static AvroSchema ofBaseType(Class extends T> tClass) {
+ Preconditions.checkArgument(SpecificRecordBase.class.isAssignableFrom(tClass));
+
+ return new AvroSchema<>(SpecificData.get().getSchema(tClass));
+ }
+
+ /**
+ * Method to create a typed AvroSchema of type {@link GenericRecord} from schema info.
+ *
+ * @param schemainfo Schema info object that has schema data in binary form.
+ * @return Returns an AvroSchema with {@link GenericRecord} type.
+ */
+ public static AvroSchema from(SchemaInfo schemainfo) {
+ String schemaString = new String(schemainfo.getSchemaData().array(), Charsets.UTF_8);
+ Schema schema = new Schema.Parser().parse(schemaString);
+
+ return new AvroSchema<>(schema);
+ }
+
+ private ByteBuffer getSchemaBytes() {
+ return ByteBuffer.wrap(schema.toString().getBytes(Charsets.UTF_8));
+ }
+
+ @Override
+ public SchemaInfo getSchemaInfo() {
+ return schemaInfo;
+ }
+}
diff --git a/serializers/src/main/java/io/pravega/schemaregistry/schemas/JSONSchema.java b/serializers/src/main/java/io/pravega/schemaregistry/schemas/JSONSchema.java
new file mode 100644
index 000000000..958208e51
--- /dev/null
+++ b/serializers/src/main/java/io/pravega/schemaregistry/schemas/JSONSchema.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) Dell Inc., or its subsidiaries. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+package io.pravega.schemaregistry.schemas;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import io.pravega.schemaregistry.contract.data.SchemaInfo;
+import io.pravega.schemaregistry.contract.data.SerializationFormat;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Container class for Json Schema.
+ *
+ * @param Type of element.
+ */
+public class JSONSchema implements SchemaContainer {
+ private final String schemaString;
+ @Getter
+ private final Class tClass;
+ @Getter
+ private final Class extends T> tDerivedClass;
+
+ @Getter
+ private final JsonSchema schema;
+
+ private final SchemaInfo schemaInfo;
+
+ private JSONSchema(JsonSchema schema, String name, String schemaString, Class tClass) {
+ this(schema, name, schemaString, tClass, tClass);
+ }
+
+ private JSONSchema(JsonSchema schema, String name, String schemaString, Class tClass, Class extends T> tDerivedClass) {
+ String type = name != null ? name : schema.getId();
+ // Add empty name if the name is not supplied and cannot be extracted from the json schema id.
+ type = type != null ? type : "";
+ this.schemaString = schemaString;
+ this.schemaInfo = new SchemaInfo(type, SerializationFormat.Json, getSchemaBytes(), ImmutableMap.of());
+ this.tClass = tClass;
+ this.tDerivedClass = tDerivedClass;
+ this.schema = schema;
+ }
+
+ /**
+ * Method to create a typed JSONSchema for the given class. It extracts the json schema from the class.
+ * For POJOs the schema is extracted using jacksons {@link JsonSchemaGenerator}.
+ *
+ * @param tClass Class whose object's schema is used.
+ * @param Type of the Java class.
+ * @return {@link JSONSchema} with generic type T that extracts and captures the json schema.
+ */
+ @SneakyThrows({JsonMappingException.class, JsonProcessingException.class})
+ public static JSONSchema of(Class tClass) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(objectMapper);
+ JsonSchema schema = schemaGen.generateSchema(tClass);
+ String schemaString = objectMapper.writeValueAsString(schema);
+
+ return new JSONSchema<>(schema, null, schemaString, tClass);
+ }
+
+ /**
+ * Method to create a typed JSONSchema of type {@link Object} from the given schema.
+ *
+ * @param type type of object identified by {@link SchemaInfo#type}.
+ * @param schemaString Schema string to use.
+ * @return Returns an JSONSchema with {@link Object} type.
+ */
+ @SneakyThrows({JsonMappingException.class, JsonProcessingException.class})
+ public static JSONSchema