/** * Copyright 2016 Hortonworks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ package com.hortonworks.registries.schemaregistry.client; import com.hortonworks.registries.schemaregistry.SchemaFieldQuery; import com.hortonworks.registries.schemaregistry.SchemaIdVersion; import com.hortonworks.registries.schemaregistry.SchemaMetadata; import com.hortonworks.registries.schemaregistry.SchemaMetadataInfo; import com.hortonworks.registries.schemaregistry.SchemaProviderInfo; import com.hortonworks.registries.schemaregistry.SchemaVersion; import com.hortonworks.registries.schemaregistry.SchemaVersionInfo; import com.hortonworks.registries.schemaregistry.SchemaVersionKey; import com.hortonworks.registries.schemaregistry.SerDesInfo; import com.hortonworks.registries.schemaregistry.SerDesPair; import com.hortonworks.registries.schemaregistry.errors.IncompatibleSchemaException; import com.hortonworks.registries.schemaregistry.errors.InvalidSchemaException; import com.hortonworks.registries.schemaregistry.errors.SchemaNotFoundException; import com.hortonworks.registries.schemaregistry.serde.SerDesException; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Collection; /** * This interface defines different methods to interact with remote schema registry. * <p> * Below code describes how to register new schemas, add new version of a schema and fetch different versions of a schema. * <pre> * * SchemaMetadata schemaMetadata = new SchemaMetadata.Builder(name) * .type(AvroSchemaProvider.TYPE) * .schemaGroup("sample-group") * .description("Sample schema") * .compatibility(SchemaProvider.Compatibility.BACKWARD) * .build(); * * // registering a new schema * Integer v1 = schemaRegistryClient.addSchemaVersion(schemaMetadata, new SchemaVersion(schema1, "Initial version of the schema")); * LOG.info("Registered schema [{}] and returned version [{}]", schema1, v1); * * // adding a new version of the schema * String schema2 = getSchema("/device-next.avsc"); * SchemaVersion schemaInfo2 = new SchemaVersion(schema2, "second version"); * Integer v2 = schemaRegistryClient.addSchemaVersion(schemaMetadata, schemaInfo2); * LOG.info("Registered schema [{}] and returned version [{}]", schema2, v2); * * //adding same schema returns the earlier registered version * Integer version = schemaRegistryClient.addSchemaVersion(schemaMetadata, schemaInfo2); * LOG.info(""); * * // get a specific version of the schema * String schemaName = schemaMetadata.getName(); * SchemaVersionInfo schemaVersionInfo = schemaRegistryClient.getSchemaVersionInfo(new SchemaVersionKey(schemaName, v2)); * * // get latest version of the schema * SchemaVersionInfo latest = schemaRegistryClient.getLatestSchemaVersionInfo(schemaName); * LOG.info("Latest schema with schema key [{}] is : [{}]", schemaMetadata, latest); * * // get all versions of the schema * Collection<SchemaVersionInfo> allVersions = schemaRegistryClient.getAllVersions(schemaName); * LOG.info("All versions of schema key [{}] is : [{}]", schemaMetadata, allVersions); * * // finding schemas containing a specific field * SchemaFieldQuery md5FieldQuery = new SchemaFieldQuery.Builder().name("md5").build(); * Collection<SchemaVersionKey> md5SchemaVersionKeys = schemaRegistryClient.findSchemasByFields(md5FieldQuery); * LOG.info("Schemas containing field query [{}] : [{}]", md5FieldQuery, md5SchemaVersionKeys); * * SchemaFieldQuery txidFieldQuery = new SchemaFieldQuery.Builder().name("txid").build(); * Collection<SchemaVersionKey> txidSchemaVersionKeys = schemaRegistryClient.findSchemasByFields(txidFieldQuery); * LOG.info("Schemas containing field query [{}] : [{}]", txidFieldQuery, txidSchemaVersionKeys); * * // Default serializer and deserializer for a given schema provider can be retrieved with the below APIs. * // for avro, * AvroSnapshotSerializer serializer = schemaRegistryClient.getDefaultSerializer(AvroSchemaProvider.TYPE); * AvroSnapshotDeserializer deserializer = schemaRegistryClient.getDefaultDeserializer(AvroSchemaProvider.TYPE); * </pre> * <p> * Below code describes how to register serializer and deserializers, map them with a schema etc. * <pre> * // upload a jar containing serializer and deserializer classes. * InputStream inputStream = new FileInputStream("/schema-custom-ser-des.jar"); * String fileId = schemaRegistryClient.uploadFile(inputStream); * * // add serializer with the respective uploaded jar file id. * SerDesInfo serializerInfo = createSerDesInfo(fileId); * Long serializerId = schemaRegistryClient.addSerializer(serializerInfo); * * // map this serializer with a registered schema * schemaRegistryClient.mapSchemaWithSerDes(schemaName, serializerId); * * // get registered serializers * Collection<SerDesInfo> serializers = schemaRegistryClient.getSerializers(schemaName); * SerDesInfo registeredSerializerInfo = serializers.iterator().next(); * * //get serializer and serialize the given payload * try(AvroSnapshotSerializer snapshotSerializer = schemaRegistryClient.createInstance(registeredSerializerInfo);) { * Map<String, Object> config = Collections.emptyMap(); * snapshotSerializer.init(config); * * byte[] serializedData = snapshotSerializer.serialize(input, schemaInfo); * * </pre> */ public interface ISchemaRegistryClient extends AutoCloseable { /** * @return Collection of supported schema providers. For ex: avro. */ Collection<SchemaProviderInfo> getSupportedSchemaProviders(); /** * Registers information about a schema. * * @param schemaMetadata information about schema. * @return true if the given {@code schemaInfo} is successfully registered now or earlier. */ Long registerSchemaMetadata(SchemaMetadata schemaMetadata); /** * @param schemaName name identifying a schema * @return information about given schema identified by {@code schemaName} */ SchemaMetadataInfo getSchemaMetadataInfo(String schemaName); /** * @param schemaMetadataId id of schema metadata * @return information about given schema identified by {@code schemaMetadataId} */ SchemaMetadataInfo getSchemaMetadataInfo(Long schemaMetadataId); /** * Returns version of the schema added with the given schemaInfo. * <pre> * It tries to fetch an existing schema or register the given schema with the below conditions * - Checks whether there exists a schema with the given name and schemaText * - returns respective schemaVersionKey if it exists. * - Creates a schema for the given name and returns respective schemaVersionKey if it does not exist. * </pre> * * @param schemaMetadata information about the schema * @param schemaVersion new version of the schema to be registered * @return version of the schema added. * @throws InvalidSchemaException if the given versionedSchema is not valid * @throws IncompatibleSchemaException if the given versionedSchema is incompatible according to the compatibility set. * @throws SchemaNotFoundException if the given schemaMetadata not found. */ SchemaIdVersion addSchemaVersion(SchemaMetadata schemaMetadata, SchemaVersion schemaVersion) throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException; /** * Uploads the given {@code schemaVersionTextFile} as a new version for the given schema with name {@code schemaName} * * @param schemaName name identifying a schema * @param description descirption about the version of this schema * @param schemaVersionTextFile FIle containing new version of the schema content. * @return version of the schema added. * @throws InvalidSchemaException if the given versionedSchema is not valid * @throws IncompatibleSchemaException if the given versionedSchema is incompatible according to the compatibility set. * @throws SchemaNotFoundException if the given schemaMetadata not found. */ public SchemaIdVersion uploadSchemaVersion(final String schemaName, final String description, final InputStream schemaVersionTextFile) throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException; /** * Adds the given {@code schemaVersion} and returns the corresponding version number. * * @param schemaName name identifying a schema * @param schemaVersion new version of the schema to be added * @return version number of the schema added * @throws InvalidSchemaException if the given schemaVersion is not valid * @throws IncompatibleSchemaException if the given schemaVersion is incompatible according to the compatibility set. * @throws SchemaNotFoundException if there is no schema metadata registered with the given {@code schemaName} */ SchemaIdVersion addSchemaVersion(String schemaName, SchemaVersion schemaVersion) throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException; /** * @param schemaFieldQuery {@link SchemaFieldQuery} instance to be run * @return schema versions matching the fields specified in the query */ Collection<SchemaVersionKey> findSchemasByFields(SchemaFieldQuery schemaFieldQuery); /** * @param schemaVersionKey key identifying a schema and a version * @return {@link SchemaVersionInfo} for the given {@link SchemaVersionKey} * @throws SchemaNotFoundException when there is no schema version exists with the given {@code schemaVersionKey} */ SchemaVersionInfo getSchemaVersionInfo(SchemaVersionKey schemaVersionKey) throws SchemaNotFoundException; /** * @param schemaName name identifying a schema * @return latest version of the schema for the given schemaName * @throws SchemaNotFoundException if there is no schema metadata registered with the given {@code schemaName} */ SchemaVersionInfo getLatestSchemaVersionInfo(String schemaName) throws SchemaNotFoundException; /** * @param schemaName name identifying a schema * @return all versions of the schemas for given schemaName * @throws SchemaNotFoundException if there is no schema metadata registered with the given {@code schemaName} */ Collection<SchemaVersionInfo> getAllVersions(String schemaName) throws SchemaNotFoundException; /** * @param schemaName name identifying a schema * @param toSchemaText text representing the schema to be checked for compatibility * @return true if the given {@code toSchemaText} is compatible with the latest version of the schema with id as {@code schemaName}. * @throws SchemaNotFoundException if there is no schema metadata registered with the given {@code schemaName} */ boolean isCompatibleWithAllVersions(String schemaName, String toSchemaText) throws SchemaNotFoundException; /** * Uploads the given {@code inputStream} of any file and returns the identifier for which it can be downloaded later * with {@link #downloadFile(String)}. * * @param inputStream input stream of a file to be uploaded. * @return unique id for the uploaded bytes read from input stream to file storage. * @throws SerDesException if any error occurs while this operation is being done. */ String uploadFile(InputStream inputStream) throws SerDesException; /** * Downloads the content of file stored with the given {@code fileId} earlier uploaded using {@link #uploadFile(InputStream)}. * * @param fileId file identifier * @return {@link InputStream} instance of the file stored earlier with {@code fileId} * @throws FileNotFoundException when there is not file stored with the given {@code fileId} */ InputStream downloadFile(String fileId) throws FileNotFoundException; /** * @param serializerInfo serializer information * @return unique id for the added Serializer for the given {@code serializerInfo} */ Long addSerDes(SerDesPair serializerInfo); /** * Maps Serializer/Deserializer of the given {@code serDesId} to Schema with {@code schemaName} * * @param schemaName name identifying a schema * @param serDesId serializer/deserializer */ void mapSchemaWithSerDes(String schemaName, Long serDesId); /** * Returns a new instance of default serializer configured for the given type of schema. * * @param type type of the schema like avro. * @param <T> class type of the serializer instance. * @return a new instance of default serializer configured * @throws SerDesException if the serializer class is not found or any error while creating an instance of serializer class. * @throws IllegalArgumentException if the given {@code type} is not registered as schema provider in the target schema registry. */ public <T> T getDefaultSerializer(String type) throws SerDesException; /** * @param type type of the schema, For ex: avro. * @param <T> class type of the deserializer instance. * @return a new instance of default deserializer configured for given {@code type} * @throws SerDesException if the deserializer class is not found or any error while creating an instance of deserializer class. * @throws IllegalArgumentException if the given {@code type} is not registered as schema provider in the target schema registry. */ public <T> T getDefaultDeserializer(String type) throws SerDesException; /** * @param schemaName name identifying a schema * @return Collection of Serializers registered for the schema with {@code schemaName} */ Collection<SerDesInfo> getSerDes(String schemaName); /** * Returns a new instance of the respective Serializer class for the given {@code serializerInfo} * * @param <T> type of the instance to be created * @param serializerInfo serializer information * @return new instance of the respective Serializer class * @throws SerDesException throws an Exception if serializer or deserializer class is not an instance of {@code T} */ <T> T createSerializerInstance(SerDesInfo serializerInfo); /** * Returns a new instance of the respective Deserializer class for the given {@code deserializerInfo} * * @param <T> type of the instance to be created * @param deserializerInfo deserializer information * @return new instance of the respective Deserializer class * @throws SerDesException throws an Exception if serializer or deserializer class is not an instance of {@code T} */ <T> T createDeserializerInstance(SerDesInfo deserializerInfo); }