diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/com/hortonworks/registries/schemaregistry/client/SchemaRegistryClient.java b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/com/hortonworks/registries/schemaregistry/client/SchemaRegistryClient.java
deleted file mode 100644
index 3471975778..0000000000
--- a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/com/hortonworks/registries/schemaregistry/client/SchemaRegistryClient.java
+++ /dev/null
@@ -1,1510 +0,0 @@
-/**
- * Copyright 2016-2019 Cloudera, Inc.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- **/
-package com.hortonworks.registries.schemaregistry.client;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.hortonworks.registries.auth.KerberosLogin;
-import com.hortonworks.registries.auth.Login;
-import com.hortonworks.registries.auth.NOOPLogin;
-import com.hortonworks.registries.auth.util.JaasConfiguration;
-import com.hortonworks.registries.common.SchemaRegistryServiceInfo;
-import com.hortonworks.registries.common.SchemaRegistryVersion;
-import com.hortonworks.registries.common.catalog.CatalogResponse;
-import com.hortonworks.registries.common.util.ClassLoaderAwareInvocationHandler;
-import com.hortonworks.registries.schemaregistry.CompatibilityResult;
-import com.hortonworks.registries.schemaregistry.ConfigEntry;
-import com.hortonworks.registries.schemaregistry.SchemaBranch;
-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.SchemaVersionMergeResult;
-import com.hortonworks.registries.schemaregistry.SchemaVersionRetriever;
-import com.hortonworks.registries.schemaregistry.SerDesInfo;
-import com.hortonworks.registries.schemaregistry.SerDesPair;
-import com.hortonworks.registries.schemaregistry.cache.SchemaVersionInfoCache;
-import com.hortonworks.registries.schemaregistry.errors.IncompatibleSchemaException;
-import com.hortonworks.registries.schemaregistry.errors.InvalidSchemaBranchDeletionException;
-import com.hortonworks.registries.schemaregistry.errors.InvalidSchemaException;
-import com.hortonworks.registries.schemaregistry.errors.SchemaBranchAlreadyExistsException;
-import com.hortonworks.registries.schemaregistry.errors.SchemaBranchNotFoundException;
-import com.hortonworks.registries.schemaregistry.errors.SchemaNotFoundException;
-import com.hortonworks.registries.schemaregistry.exceptions.RegistryRetryableException;
-import com.hortonworks.registries.schemaregistry.serde.SerDesException;
-import com.hortonworks.registries.schemaregistry.serde.SnapshotDeserializer;
-import com.hortonworks.registries.schemaregistry.serde.SnapshotSerializer;
-import com.hortonworks.registries.schemaregistry.serde.pull.PullDeserializer;
-import com.hortonworks.registries.schemaregistry.serde.pull.PullSerializer;
-import com.hortonworks.registries.schemaregistry.serde.push.PushDeserializer;
-import com.hortonworks.registries.schemaregistry.state.SchemaLifecycleException;
-import com.hortonworks.registries.schemaregistry.state.SchemaVersionLifecycleStateMachineInfo;
-import org.apache.commons.io.IOUtils;
-import org.apache.nifi.util.security.MessageDigestUtils;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.media.multipart.BodyPart;
-import org.glassfish.jersey.media.multipart.FormDataMultiPart;
-import org.glassfish.jersey.media.multipart.MultiPart;
-import org.glassfish.jersey.media.multipart.MultiPartFeature;
-import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.Yaml;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLContext;
-import javax.security.auth.login.LoginException;
-import javax.ws.rs.BadRequestException;
-import javax.ws.rs.NotFoundException;
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.client.Entity;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Proxy;
-import java.net.URLEncoder;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-
-import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.DEFAULT_CONNECTION_TIMEOUT;
-import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.DEFAULT_READ_TIMEOUT;
-import static com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient.Configuration.SCHEMA_REGISTRY_URL;
-
-/**
- * NOTE: This class is a copy of the SchemaRegistryClient from https://github.com/hortonworks/registry.
- * The changes to this file are the following:
- * - Making the 'private Login login' become protected for access by sub-classes
- * - Making the 'private Configuration configuration' become protected for access by sub-classes
- *
- * This is the default implementation of {@link ISchemaRegistryClient} which connects to the given {@code rootCatalogURL}.
- *
- * An instance of SchemaRegistryClient can be instantiated by passing configuration properties like below.
- *
- * SchemaRegistryClient schemaRegistryClient = new SchemaRegistryClient(config);
- *
- *
- * There are different options available as mentioned in {@link Configuration} like
- *
- * - {@link Configuration#SCHEMA_REGISTRY_URL}.
- * - {@link Configuration#SCHEMA_METADATA_CACHE_SIZE}.
- * - {@link Configuration#SCHEMA_METADATA_CACHE_EXPIRY_INTERVAL_SECS}.
- * - {@link Configuration#SCHEMA_VERSION_CACHE_SIZE}.
- * - {@link Configuration#SCHEMA_VERSION_CACHE_EXPIRY_INTERVAL_SECS}.
- * - {@link Configuration#SCHEMA_TEXT_CACHE_SIZE}.
- * - {@link Configuration#SCHEMA_TEXT_CACHE_EXPIRY_INTERVAL_SECS}.
- *
- * and many other properties like {@link ClientProperties}
- *
- *
- * This can be used to
- * - register schema metadata
- * - add new versions of a schema
- * - fetch different versions of schema
- * - fetch latest version of a schema
- * - check whether the given schema text is compatible with a latest version of the schema
- * - register serializer/deserializer for a schema
- * - fetch serializer/deserializer for a schema
- *
- */
-public class SchemaRegistryClient implements ISchemaRegistryClient {
- private static final Logger LOG = LoggerFactory.getLogger(SchemaRegistryClient.class);
-
- private static final String SCHEMA_REGISTRY_PATH = "/schemaregistry";
- private static final String SCHEMAS_PATH = SCHEMA_REGISTRY_PATH + "/schemas/";
- private static final String SCHEMA_PROVIDERS_PATH = SCHEMA_REGISTRY_PATH + "/schemaproviders/";
- private static final String SCHEMAS_BY_ID_PATH = SCHEMA_REGISTRY_PATH + "/schemasById/";
- private static final String SCHEMA_VERSIONS_PATH = SCHEMAS_PATH + "versions/";
- private static final String FILES_PATH = SCHEMA_REGISTRY_PATH + "/files/";
- private static final String SERIALIZERS_PATH = SCHEMA_REGISTRY_PATH + "/serdes/";
- private static final String REGISTY_CLIENT_JAAS_SECTION = "RegistryClient";
- private static final Set> DESERIALIZER_INTERFACE_CLASSES = new LinkedHashSet<>(Arrays.asList(SnapshotDeserializer.class, PullDeserializer.class, PushDeserializer.class));
- private static final Set> SERIALIZER_INTERFACE_CLASSES = new LinkedHashSet<>(Arrays.asList(SnapshotSerializer.class, PullSerializer.class));
- private static final String SEARCH_FIELDS = SCHEMA_REGISTRY_PATH + "/search/schemas/fields";
- private static final long KERBEROS_SYNCHRONIZATION_TIMEOUT_MS = 180000;
-
- private static final String SSL_KEY_PASSWORD = "keyPassword";
- private static final String SSL_KEY_STORE_PATH = "keyStorePath";
-
- private static final SchemaRegistryVersion CLIENT_VERSION = SchemaRegistryServiceInfo.get().version();
-
- protected Login login;
- private final Client client;
- private final UrlSelector urlSelector;
- private final Map urlWithTargets;
-
- protected final Configuration configuration;
- private final ClassLoaderCache classLoaderCache;
- private final SchemaVersionInfoCache schemaVersionInfoCache;
- private final SchemaMetadataCache schemaMetadataCache;
- private final Cache schemaTextCache;
-
- private static final String SSL_CONFIGURATION_KEY = "schema.registry.client.ssl";
- private static final String HOSTNAME_VERIFIER_CLASS_KEY = "hostnameVerifierClass";
-
- /**
- * Creates {@link SchemaRegistryClient} instance with the given yaml config.
- *
- * @param confFile config file which contains the configuration entries.
- *
- * @throws IOException when any IOException occurs while reading the given confFile
- */
- public SchemaRegistryClient(File confFile) throws IOException {
- this(buildConfFromFile(confFile));
- }
-
- private static Map buildConfFromFile(File confFile) throws IOException {
- try (FileInputStream fis = new FileInputStream(confFile)) {
- return (Map) new Yaml().load(IOUtils.toString(fis, "UTF-8"));
- }
- }
-
- public SchemaRegistryClient(Map conf) {
- configuration = new Configuration(conf);
- initializeSecurityContext();
- ClientConfig config = createClientConfig(conf);
- ClientBuilder clientBuilder = JerseyClientBuilder.newBuilder()
- .withConfig(config)
- .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE);
- if (conf.containsKey(SSL_CONFIGURATION_KEY)) {
- Map sslConfigurations = (Map) conf.get(SSL_CONFIGURATION_KEY);
- clientBuilder.sslContext(createSSLContext(sslConfigurations));
- if (sslConfigurations.containsKey(HOSTNAME_VERIFIER_CLASS_KEY)) {
- HostnameVerifier hostNameVerifier = null;
- String hostNameVerifierClassName = sslConfigurations.get(HOSTNAME_VERIFIER_CLASS_KEY);
- try {
- hostNameVerifier = (HostnameVerifier) Class.forName(hostNameVerifierClassName).newInstance();
- } catch (Exception e) {
- throw new RuntimeException("Failed to instantiate hostNameVerifierClass : " + hostNameVerifierClassName, e);
- }
- clientBuilder.hostnameVerifier(hostNameVerifier);
- }
- }
- client = clientBuilder.build();
- client.register(MultiPartFeature.class);
-
- // get list of urls and create given or default UrlSelector.
- urlSelector = createUrlSelector();
- urlWithTargets = new ConcurrentHashMap<>();
-
- classLoaderCache = new ClassLoaderCache(this);
-
- schemaVersionInfoCache = new SchemaVersionInfoCache(
- new SchemaVersionRetriever() {
- @Override
- public SchemaVersionInfo retrieveSchemaVersion(SchemaVersionKey key) throws SchemaNotFoundException {
- return doGetSchemaVersionInfo(key);
- }
-
- @Override
- public SchemaVersionInfo retrieveSchemaVersion(SchemaIdVersion key) throws SchemaNotFoundException {
- return doGetSchemaVersionInfo(key);
- }
- },
- ((Number) configuration.getValue(Configuration.SCHEMA_VERSION_CACHE_SIZE.name())).intValue(),
- ((Number) configuration.getValue(Configuration.SCHEMA_VERSION_CACHE_EXPIRY_INTERVAL_SECS.name())).longValue() * 1000L
- );
-
- SchemaMetadataCache.SchemaMetadataFetcher schemaMetadataFetcher = createSchemaMetadataFetcher();
- schemaMetadataCache = new SchemaMetadataCache(((Number) configuration.getValue(Configuration.SCHEMA_METADATA_CACHE_SIZE
- .name())).longValue(),
- ((Number) configuration.getValue(Configuration.SCHEMA_METADATA_CACHE_EXPIRY_INTERVAL_SECS
- .name())).longValue(),
- schemaMetadataFetcher);
-
- schemaTextCache = Caffeine.newBuilder()
- .maximumSize(((Number) configuration.getValue(Configuration.SCHEMA_TEXT_CACHE_SIZE
- .name())).longValue())
- .expireAfterAccess(((Number) configuration.getValue(Configuration.SCHEMA_TEXT_CACHE_EXPIRY_INTERVAL_SECS
- .name())).longValue(),
- TimeUnit.SECONDS)
- .build();
- }
-
- protected void initializeSecurityContext() {
- String saslJaasConfig = configuration.getValue(Configuration.SASL_JAAS_CONFIG.name());
- if (saslJaasConfig != null) {
- KerberosLogin kerberosLogin = new KerberosLogin(KERBEROS_SYNCHRONIZATION_TIMEOUT_MS);
- try {
- kerberosLogin.configure(new HashMap<>(), REGISTY_CLIENT_JAAS_SECTION, new JaasConfiguration(REGISTY_CLIENT_JAAS_SECTION, saslJaasConfig));
- kerberosLogin.login();
- login = kerberosLogin;
- return;
- } catch (LoginException e) {
- LOG.error("Failed to initialize the dynamic JAAS config: " + saslJaasConfig + ". Attempting static JAAS config.");
- } catch (Exception e) {
- LOG.error("Failed to parse the dynamic JAAS config. Attempting static JAAS config.", e);
- }
- }
-
- String jaasConfigFile = System.getProperty("java.security.auth.login.config");
- if (jaasConfigFile != null && !jaasConfigFile.trim().isEmpty()) {
- KerberosLogin kerberosLogin = new KerberosLogin(KERBEROS_SYNCHRONIZATION_TIMEOUT_MS);
- kerberosLogin.configure(new HashMap<>(), REGISTY_CLIENT_JAAS_SECTION);
- try {
- kerberosLogin.login();
- login = kerberosLogin;
- } catch (LoginException e) {
- LOG.error("Could not login using jaas config section " + REGISTY_CLIENT_JAAS_SECTION);
- login = new NOOPLogin();
- }
- } else {
- LOG.warn("System property for jaas config file is not defined. Its okay if schema registry is not running in secured mode");
- login = new NOOPLogin();
- }
- }
-
- protected SSLContext createSSLContext(Map sslConfigurations) {
- SslConfigurator sslConfigurator = SslConfigurator.newInstance();
- if (sslConfigurations.containsKey(SSL_KEY_STORE_PATH)) {
- sslConfigurator.keyStoreType(sslConfigurations.get("keyStoreType"))
- .keyStoreFile(sslConfigurations.get(SSL_KEY_STORE_PATH))
- .keyStorePassword(sslConfigurations.get("keyStorePassword"))
- .keyStoreProvider(sslConfigurations.get("keyStoreProvider"))
- .keyManagerFactoryAlgorithm(sslConfigurations.get("keyManagerFactoryAlgorithm"))
- .keyManagerFactoryProvider(sslConfigurations.get("keyManagerFactoryProvider"));
- if (sslConfigurations.containsKey(SSL_KEY_PASSWORD)) {
- sslConfigurator.keyPassword(sslConfigurations.get(SSL_KEY_PASSWORD));
- }
- }
-
-
- sslConfigurator.trustStoreType(sslConfigurations.get("trustStoreType"))
- .trustStoreFile(sslConfigurations.get("trustStorePath"))
- .trustStorePassword(sslConfigurations.get("trustStorePassword"))
- .trustStoreProvider(sslConfigurations.get("trustStoreProvider"))
- .trustManagerFactoryAlgorithm(sslConfigurations.get("trustManagerFactoryAlgorithm"))
- .trustManagerFactoryProvider(sslConfigurations.get("trustManagerFactoryProvider"));
-
- sslConfigurator.securityProtocol(sslConfigurations.get("protocol"));
-
- return sslConfigurator.createSSLContext();
- }
-
- private SchemaRegistryTargets currentSchemaRegistryTargets() {
- String url = urlSelector.select();
- urlWithTargets.computeIfAbsent(url, s -> new SchemaRegistryTargets(client.target(s)));
- return urlWithTargets.get(url);
- }
-
- private static class SchemaRegistryTargets {
- private final WebTarget schemaProvidersTarget;
- private final WebTarget schemasTarget;
- private final WebTarget schemasByIdTarget;
- private final WebTarget rootTarget;
- private final WebTarget searchFieldsTarget;
- private final WebTarget serializersTarget;
- private final WebTarget filesTarget;
- private final WebTarget schemaVersionsTarget;
- private final WebTarget schemaVersionsByIdTarget;
- private final WebTarget schemaVersionsStatesMachineTarget;
-
- SchemaRegistryTargets(WebTarget rootTarget) {
- this.rootTarget = rootTarget;
- schemaProvidersTarget = rootTarget.path(SCHEMA_PROVIDERS_PATH);
- schemasTarget = rootTarget.path(SCHEMAS_PATH);
- schemasByIdTarget = rootTarget.path(SCHEMAS_BY_ID_PATH);
- schemaVersionsByIdTarget = schemasTarget.path("versionsById");
- schemaVersionsTarget = rootTarget.path(SCHEMA_VERSIONS_PATH);
- schemaVersionsStatesMachineTarget = schemaVersionsTarget.path("statemachine");
- searchFieldsTarget = rootTarget.path(SEARCH_FIELDS);
- serializersTarget = rootTarget.path(SERIALIZERS_PATH);
- filesTarget = rootTarget.path(FILES_PATH);
- }
-
- }
-
- private UrlSelector createUrlSelector() {
- UrlSelector urlSelector = null;
- String rootCatalogURL = configuration.getValue(SCHEMA_REGISTRY_URL.name());
- String urlSelectorClass = configuration.getValue(Configuration.URL_SELECTOR_CLASS.name());
- if (urlSelectorClass == null) {
- urlSelector = new LoadBalancedFailoverUrlSelector(rootCatalogURL);
- } else {
- try {
- urlSelector = (UrlSelector) Class.forName(urlSelectorClass)
- .getConstructor(String.class)
- .newInstance(rootCatalogURL);
- } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException
- | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
- urlSelector.init(configuration.getConfig());
-
- return urlSelector;
- }
-
- private SchemaMetadataCache.SchemaMetadataFetcher createSchemaMetadataFetcher() {
- return new SchemaMetadataCache.SchemaMetadataFetcher() {
- @Override
- public SchemaMetadataInfo fetch(String name) throws SchemaNotFoundException {
- try {
- return getEntity(currentSchemaRegistryTargets().schemasTarget.path(name), SchemaMetadataInfo.class);
- } catch (NotFoundException e) {
- throw new SchemaNotFoundException(e);
- }
- }
-
- @Override
- public SchemaMetadataInfo fetch(Long id) throws SchemaNotFoundException {
- try {
- return getEntity(currentSchemaRegistryTargets().schemasByIdTarget.path(id.toString()), SchemaMetadataInfo.class);
- } catch (NotFoundException e) {
- throw new SchemaNotFoundException(e);
- }
- }
- };
- }
-
- protected ClientConfig createClientConfig(Map conf) {
- ClientConfig config = new ClientConfig();
- config.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
- config.property(ClientProperties.READ_TIMEOUT, DEFAULT_READ_TIMEOUT);
- config.property(ClientProperties.FOLLOW_REDIRECTS, true);
- for (Map.Entry entry : conf.entrySet()) {
- config.property(entry.getKey(), entry.getValue());
- }
- return config;
- }
-
- public Configuration getConfiguration() {
- return configuration;
- }
-
- @Override
- public Collection getSupportedSchemaProviders() {
- return getEntities(currentSchemaRegistryTargets().schemaProvidersTarget, SchemaProviderInfo.class);
- }
-
- @Override
- public Long registerSchemaMetadata(SchemaMetadata schemaMetadata) {
- return addSchemaMetadata(schemaMetadata);
- }
-
- @Override
- public Long addSchemaMetadata(SchemaMetadata schemaMetadata) {
- SchemaMetadataInfo schemaMetadataInfo = schemaMetadataCache.getIfPresent(SchemaMetadataCache.Key.of(schemaMetadata
- .getName()));
- if (schemaMetadataInfo == null) {
- return doRegisterSchemaMetadata(schemaMetadata, currentSchemaRegistryTargets().schemasTarget);
- }
-
- return schemaMetadataInfo.getId();
- }
-
- @Override
- public SchemaMetadataInfo updateSchemaMetadata(String schemaName, SchemaMetadata schemaMetadata) {
- SchemaMetadataInfo schemaMetadataInfo = postEntity(currentSchemaRegistryTargets().schemasTarget.path(schemaName), schemaMetadata, SchemaMetadataInfo.class);
- if (schemaMetadataInfo != null) {
- schemaMetadataCache.put(SchemaMetadataCache.Key.of(schemaName), schemaMetadataInfo);
- }
- return schemaMetadataInfo;
- }
-
-
- private Long doRegisterSchemaMetadata(SchemaMetadata schemaMetadata, WebTarget schemasTarget) {
- try {
- return postEntity(schemasTarget, schemaMetadata, Long.class);
- } catch(BadRequestException ex) {
- Response response = ex.getResponse();
- CatalogResponse catalogResponse = SchemaRegistryClient.readCatalogResponse(response.readEntity(String.class));
- if(catalogResponse.getResponseCode() == CatalogResponse.ResponseMessage.ENTITY_CONFLICT.getCode()) {
- return getSchemaMetadataInfo(schemaMetadata.getName()).getId();
- } else {
- throw ex;
- }
- }
- }
-
- @Override
- public SchemaMetadataInfo getSchemaMetadataInfo(String schemaName) {
- return schemaMetadataCache.get(SchemaMetadataCache.Key.of(schemaName));
- }
-
- @Override
- public SchemaMetadataInfo getSchemaMetadataInfo(Long schemaMetadataId) {
- return schemaMetadataCache.get(SchemaMetadataCache.Key.of(schemaMetadataId));
- }
-
- @Override
- public void deleteSchema(String schemaName) throws SchemaNotFoundException {
- Collection schemaVersionInfos = getAllVersions(schemaName);
- schemaMetadataCache.invalidateSchemaMetadata(SchemaMetadataCache.Key.of(schemaName));
- if (schemaVersionInfos != null) {
- for (SchemaVersionInfo schemaVersionInfo: schemaVersionInfos) {
- SchemaIdVersion schemaIdVersion = new SchemaIdVersion(schemaVersionInfo.getId());
- schemaVersionInfoCache.invalidateSchema(SchemaVersionInfoCache.Key.of(schemaIdVersion));
- }
- }
-
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(String.format("%s", schemaName));
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).delete(Response.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- int status = response.getStatus();
- if (status == Response.Status.NOT_FOUND.getStatusCode()) {
- throw new SchemaNotFoundException(response.readEntity(String.class));
- } else if (status == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
- throw new RuntimeException(response.readEntity(String.class));
- }
- }
-
- @Override
- public SchemaIdVersion addSchemaVersion(SchemaMetadata schemaMetadata, SchemaVersion schemaVersion, boolean disableCanonicalCheck) throws
- InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
- return addSchemaVersion(SchemaBranch.MASTER_BRANCH, schemaMetadata, schemaVersion, disableCanonicalCheck);
- }
-
- @Override
- public SchemaIdVersion addSchemaVersion(String schemaBranchName, SchemaMetadata schemaMetadata, SchemaVersion schemaVersion, boolean disableCanonicalCheck) throws
- InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
- // get it, if it exists in cache
- SchemaDigestEntry schemaDigestEntry = buildSchemaTextEntry(schemaVersion, schemaMetadata.getName());
- SchemaIdVersion schemaIdVersion = schemaTextCache.getIfPresent(schemaDigestEntry);
-
- if (schemaIdVersion == null) {
- //register schema metadata if it does not exist
- Long metadataId = registerSchemaMetadata(schemaMetadata);
- if (metadataId == null) {
- LOG.error("Schema Metadata [{}] is not registered successfully", schemaMetadata);
- throw new RuntimeException("Given SchemaMetadata could not be registered: " + schemaMetadata);
- }
-
- // add schemaIdVersion
- schemaIdVersion = addSchemaVersion(schemaBranchName, schemaMetadata.getName(), schemaVersion, disableCanonicalCheck);
- }
-
- return schemaIdVersion;
- }
-
- @Override
- public SchemaIdVersion uploadSchemaVersion(String schemaName, String description, InputStream schemaVersionTextFile) throws
- InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
- return uploadSchemaVersion(SchemaBranch.MASTER_BRANCH, schemaName, description, schemaVersionTextFile);
- }
-
- public SchemaIdVersion uploadSchemaVersion(final String schemaBranchName,
- final String schemaName,
- final String description,
- final InputStream schemaVersionInputStream)
- throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
-
- SchemaMetadataInfo schemaMetadataInfo = getSchemaMetadataInfo(schemaName);
- if (schemaMetadataInfo == null) {
- throw new SchemaNotFoundException("Schema with name " + schemaName + " not found");
- }
-
- StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", schemaVersionInputStream);
-
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(schemaName).path("/versions/upload").queryParam("branch",schemaBranchName);
- MultiPart multipartEntity =
- new FormDataMultiPart()
- .field("description", description, MediaType.APPLICATION_JSON_TYPE)
- .bodyPart(streamDataBodyPart);
-
- Entity multiPartEntity = Entity.entity(multipartEntity, MediaType.MULTIPART_FORM_DATA);
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request().post(multiPartEntity, Response.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- return handleSchemaIdVersionResponse(schemaMetadataInfo, response);
- }
-
- private SchemaDigestEntry buildSchemaTextEntry(SchemaVersion schemaVersion, String name) {
- byte[] digest;
- try {
- digest = MessageDigestUtils.getDigest(schemaVersion.getSchemaText().getBytes("UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
-
- // storing schema text string is expensive, so storing digest in cache's key.
- return new SchemaDigestEntry(name, digest);
- }
-
- @Override
- public SchemaIdVersion addSchemaVersion(final String schemaName, final SchemaVersion schemaVersion, boolean disableCanonicalCheck)
- throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
- return addSchemaVersion(SchemaBranch.MASTER_BRANCH, schemaName, schemaVersion, disableCanonicalCheck);
- }
-
- @Override
- public SchemaIdVersion addSchemaVersion(final String schemaBranchName, final String schemaName, final SchemaVersion schemaVersion, boolean disableCanonicalCheck)
- throws InvalidSchemaException, IncompatibleSchemaException, SchemaNotFoundException, SchemaBranchNotFoundException {
-
- try {
- return schemaTextCache.get(buildSchemaTextEntry(schemaVersion, schemaName),
- key -> {
- try {
- return doAddSchemaVersion(schemaBranchName, schemaName, schemaVersion, disableCanonicalCheck);
- } catch (final Exception e) {
- LOG.error("Encountered error while adding new version [{}] of schema [{}] and error [{}]", schemaVersion, schemaName, e);
- throw new RuntimeException(e);
- }
- });
- } catch (final RuntimeException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof InvalidSchemaException)
- throw (InvalidSchemaException) cause;
- else if (cause instanceof IncompatibleSchemaException) {
- throw (IncompatibleSchemaException) cause;
- } else if (cause instanceof SchemaNotFoundException) {
- throw (SchemaNotFoundException) cause;
- } else {
- throw e;
- }
- }
- }
-
- @Override
- public void deleteSchemaVersion(SchemaVersionKey schemaVersionKey) throws SchemaNotFoundException, SchemaLifecycleException {
- schemaVersionInfoCache.invalidateSchema(new SchemaVersionInfoCache.Key(schemaVersionKey));
-
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(String.format("%s/versions/%s", schemaVersionKey
- .getSchemaName(), schemaVersionKey.getVersion()));
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).delete(Response.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- handleDeleteSchemaResponse(response);
- }
-
- private void handleDeleteSchemaResponse(Response response) throws SchemaNotFoundException, SchemaLifecycleException {
- String msg = response.readEntity(String.class);
- switch (Response.Status.fromStatusCode(response.getStatus())) {
- case NOT_FOUND:
- throw new SchemaNotFoundException(msg);
- case BAD_REQUEST:
- throw new SchemaLifecycleException(msg);
- case INTERNAL_SERVER_ERROR:
- throw new RuntimeException(msg);
- }
- }
-
- private SchemaIdVersion doAddSchemaVersion(String schemaBranchName, String schemaName,
- SchemaVersion schemaVersion, boolean disableCanonicalCheck) throws IncompatibleSchemaException, InvalidSchemaException, SchemaNotFoundException {
- SchemaMetadataInfo schemaMetadataInfo = getSchemaMetadataInfo(schemaName);
- if (schemaMetadataInfo == null) {
- throw new SchemaNotFoundException("Schema with name " + schemaName + " not found");
- }
-
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(schemaName).path("/versions").queryParam("branch", schemaBranchName)
- .queryParam("disableCanonicalCheck", disableCanonicalCheck);
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(schemaVersion), Response.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- return handleSchemaIdVersionResponse(schemaMetadataInfo, response);
- }
-
- private SchemaIdVersion handleSchemaIdVersionResponse(SchemaMetadataInfo schemaMetadataInfo,
- Response response) throws IncompatibleSchemaException, InvalidSchemaException {
- int status = response.getStatus();
- String msg = response.readEntity(String.class);
- if (status == Response.Status.BAD_REQUEST.getStatusCode() || status == Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
- CatalogResponse catalogResponse = readCatalogResponse(msg);
- if (CatalogResponse.ResponseMessage.INCOMPATIBLE_SCHEMA.getCode() == catalogResponse.getResponseCode()) {
- throw new IncompatibleSchemaException(catalogResponse.getResponseMessage());
- } else if (CatalogResponse.ResponseMessage.INVALID_SCHEMA.getCode() == catalogResponse.getResponseCode()) {
- throw new InvalidSchemaException(catalogResponse.getResponseMessage());
- } else {
- throw new RuntimeException(catalogResponse.getResponseMessage());
- }
-
- }
-
- Integer version = readEntity(msg, Integer.class);
-
- SchemaVersionInfo schemaVersionInfo = doGetSchemaVersionInfo(new SchemaVersionKey(schemaMetadataInfo.getSchemaMetadata()
- .getName(), version));
-
- return new SchemaIdVersion(schemaMetadataInfo.getId(), version, schemaVersionInfo.getId());
- }
-
- public static CatalogResponse readCatalogResponse(String msg) {
- ObjectMapper objectMapper = new ObjectMapper();
- try {
- JsonNode node = objectMapper.readTree(msg);
-
- return objectMapper.treeToValue(node, CatalogResponse.class);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public SchemaVersionInfo getSchemaVersionInfo(SchemaIdVersion schemaIdVersion) throws SchemaNotFoundException {
- try {
- return schemaVersionInfoCache.getSchema(SchemaVersionInfoCache.Key.of(schemaIdVersion));
- } catch (SchemaNotFoundException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- @Override
- public SchemaVersionInfo getLatestSchemaVersionInfo(String schemaName) throws SchemaNotFoundException {
- return getLatestSchemaVersionInfo(SchemaBranch.MASTER_BRANCH, schemaName);
- }
-
- @Override
- public SchemaVersionInfo getSchemaVersionInfo(SchemaVersionKey schemaVersionKey) throws SchemaNotFoundException {
- try {
- return schemaVersionInfoCache.getSchema(SchemaVersionInfoCache.Key.of(schemaVersionKey));
- } catch (SchemaNotFoundException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private SchemaVersionInfo doGetSchemaVersionInfo(SchemaIdVersion schemaIdVersion) throws SchemaNotFoundException {
- if (schemaIdVersion.getSchemaVersionId() != null) {
- LOG.info("Getting schema version from target registry for [{}]", schemaIdVersion.getSchemaVersionId());
- return getEntity(currentSchemaRegistryTargets()
- .schemaVersionsByIdTarget
- .path(schemaIdVersion.getSchemaVersionId().toString()),
- SchemaVersionInfo.class);
- } else if (schemaIdVersion.getSchemaMetadataId() != null) {
- SchemaMetadataInfo schemaMetadataInfo = getSchemaMetadataInfo(schemaIdVersion.getSchemaMetadataId());
- SchemaVersionKey schemaVersionKey = new SchemaVersionKey(schemaMetadataInfo.getSchemaMetadata()
- .getName(), schemaIdVersion.getVersion());
- LOG.info("Getting schema version from target registry for key [{}]", schemaVersionKey);
- return doGetSchemaVersionInfo(schemaVersionKey);
- }
-
- throw new IllegalArgumentException("Given argument not valid: " + schemaIdVersion);
- }
-
- private SchemaVersionInfo doGetSchemaVersionInfo(SchemaVersionKey schemaVersionKey) {
- LOG.info("Getting schema version from target registry for [{}]", schemaVersionKey);
- String schemaName = schemaVersionKey.getSchemaName();
- WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget.path(String.format("%s/versions/%d", schemaName, schemaVersionKey
- .getVersion()));
-
- return getEntity(webTarget, SchemaVersionInfo.class);
- }
-
- @Override
- public SchemaVersionInfo getLatestSchemaVersionInfo(String schemaBranchName, String schemaName) throws SchemaNotFoundException {
- WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaName) + "/versions/latest").queryParam("branch", schemaBranchName);;
- return getEntity(webTarget, SchemaVersionInfo.class);
- }
-
- @Override
- public Collection getAllVersions(String schemaName) throws SchemaNotFoundException {
- return getAllVersions(SchemaBranch.MASTER_BRANCH, schemaName);
- }
-
- private static String encode(String schemaName) {
- try {
- return URLEncoder.encode(schemaName, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void enableSchemaVersion(Long schemaVersionId)
- throws SchemaNotFoundException, SchemaLifecycleException, IncompatibleSchemaException {
- try {
- transitionSchemaVersionState(schemaVersionId, "enable", null);
- } catch (SchemaLifecycleException e) {
- Throwable cause = e.getCause();
- if (cause != null && cause instanceof IncompatibleSchemaException) {
- throw (IncompatibleSchemaException) cause;
- }
- throw e;
- }
- }
-
- @Override
- public void disableSchemaVersion(Long schemaVersionId) throws SchemaNotFoundException, SchemaLifecycleException {
- transitionSchemaVersionState(schemaVersionId, "disable", null);
- }
-
- @Override
- public void deleteSchemaVersion(Long schemaVersionId) throws SchemaNotFoundException, SchemaLifecycleException {
- transitionSchemaVersionState(schemaVersionId, "delete", null);
- }
-
- @Override
- public void archiveSchemaVersion(Long schemaVersionId) throws SchemaNotFoundException, SchemaLifecycleException {
- transitionSchemaVersionState(schemaVersionId, "archive", null);
- }
-
- @Override
- public void startSchemaVersionReview(Long schemaVersionId) throws SchemaNotFoundException, SchemaLifecycleException {
- transitionSchemaVersionState(schemaVersionId, "startReview", null);
- }
-
- @Override
- public SchemaVersionMergeResult mergeSchemaVersion(Long schemaVersionId, boolean disableCanonicalCheck) throws SchemaNotFoundException, IncompatibleSchemaException {
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(schemaVersionId + "/merge").queryParam("disableCanonicalCheck", disableCanonicalCheck);
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request().post(null);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- int status = response.getStatus();
- if (status == Response.Status.OK.getStatusCode()) {
- String msg = response.readEntity(String.class);
- return readEntity(msg, SchemaVersionMergeResult.class);
- } else if (status == Response.Status.NOT_FOUND.getStatusCode()) {
- throw new SchemaNotFoundException(response.readEntity(String.class));
- } else if (status == Response.Status.BAD_REQUEST.getStatusCode()) {
- throw new IncompatibleSchemaException(response.readEntity(String.class));
- } else {
- throw new RuntimeException(response.readEntity(String.class));
- }
- }
-
- @Override
- public void transitionState(Long schemaVersionId,
- Byte targetStateId,
- byte[] transitionDetails) throws SchemaNotFoundException, SchemaLifecycleException {
- boolean result = transitionSchemaVersionState(schemaVersionId, targetStateId.toString(), transitionDetails);
- }
-
- @Override
- public SchemaVersionLifecycleStateMachineInfo getSchemaVersionLifecycleStateMachineInfo() {
- return getEntity(currentSchemaRegistryTargets().schemaVersionsStatesMachineTarget,
- SchemaVersionLifecycleStateMachineInfo.class);
- }
-
- @Override
- public SchemaBranch createSchemaBranch(Long schemaVersionId, SchemaBranch schemaBranch) throws SchemaBranchAlreadyExistsException, SchemaNotFoundException {
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path("versionsById/" + schemaVersionId + "/branch");
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(schemaBranch), Response.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- int status = response.getStatus();
- if (status == Response.Status.OK.getStatusCode()) {
- String msg = response.readEntity(String.class);
- SchemaBranch returnedSchemaBranch = readEntity(msg, SchemaBranch.class);
- return returnedSchemaBranch;
- } else if (status == Response.Status.BAD_REQUEST.getStatusCode()) {
- throw new SchemaNotFoundException(response.readEntity(String.class));
- } else if (status == Response.Status.CONFLICT.getStatusCode()) {
- throw new SchemaBranchAlreadyExistsException(response.readEntity(String.class));
- } else {
- throw new RuntimeException(response.readEntity(String.class));
- }
- }
-
- @Override
- public Collection getSchemaBranches(String schemaName) throws SchemaNotFoundException {
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaName) + "/branches");
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request().get();
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- int status = response.getStatus();
- if (status == Response.Status.NOT_FOUND.getStatusCode()) {
- throw new SchemaNotFoundException(response.readEntity(String.class));
- } else if (status != Response.Status.OK.getStatusCode()) {
- throw new RuntimeException(response.readEntity(String.class));
- }
-
- return parseResponseAsEntities(response.readEntity(String.class), SchemaBranch.class);
- }
-
- @Override
- public void deleteSchemaBranch(Long schemaBranchId) throws SchemaBranchNotFoundException, InvalidSchemaBranchDeletionException {
- WebTarget target = currentSchemaRegistryTargets().schemasTarget.path("branch/" + schemaBranchId);
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return target.request().delete();
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- int status = response.getStatus();
- if (status == Response.Status.NOT_FOUND.getStatusCode()) {
- throw new SchemaBranchNotFoundException(response.readEntity(String.class));
- } else if (status == Response.Status.BAD_REQUEST.getStatusCode()) {
- throw new InvalidSchemaBranchDeletionException(response.readEntity(String.class));
- } else if (status != Response.Status.OK.getStatusCode()) {
- throw new RuntimeException(response.readEntity(String.class));
- }
-
- }
-
- @Override
- public Collection getAllVersions(String schemaBranchName, String schemaName, List stateIds) throws SchemaNotFoundException, SchemaBranchNotFoundException {
- WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaName) + "/versions").queryParam("branch", schemaBranchName).queryParam("states", stateIds.toArray());
- return getEntities(webTarget, SchemaVersionInfo.class);
- }
-
- private boolean transitionSchemaVersionState(Long schemaVersionId,
- String operationOrTargetState,
- byte[] transitionDetails) throws SchemaNotFoundException, SchemaLifecycleException {
-
- WebTarget webTarget = currentSchemaRegistryTargets().schemaVersionsTarget.path(schemaVersionId + "/state/" + operationOrTargetState);
- Response response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public Response run() {
- return webTarget.request().post(Entity.text(transitionDetails));
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- boolean result = handleSchemaLifeCycleResponse(response);
-
- // invalidate this entry from cache.
- schemaVersionInfoCache.invalidateSchema(SchemaVersionInfoCache.Key.of(new SchemaIdVersion(schemaVersionId)));
-
- return result;
- }
-
- private boolean handleSchemaLifeCycleResponse(Response response) throws SchemaNotFoundException, SchemaLifecycleException {
- boolean result;
- int status = response.getStatus();
- if (status == Response.Status.OK.getStatusCode()) {
- result = response.readEntity(Boolean.class);
- } else if (status == Response.Status.NOT_FOUND.getStatusCode()) {
- throw new SchemaNotFoundException(response.readEntity(String.class));
- } else if (status == Response.Status.BAD_REQUEST.getStatusCode()) {
- CatalogResponse catalogResponse = readCatalogResponse(response.readEntity(String.class));
- if (catalogResponse.getResponseCode() == CatalogResponse.ResponseMessage.INCOMPATIBLE_SCHEMA.getCode()) {
- throw new SchemaLifecycleException(new IncompatibleSchemaException(catalogResponse.getResponseMessage()));
- }
- throw new SchemaLifecycleException(catalogResponse.getResponseMessage());
-
- } else {
- throw new RuntimeException(response.readEntity(String.class));
- }
-
- return result;
- }
-
- @Override
- public Collection getAllVersions(String schemaBranchName, String schemaName) throws SchemaNotFoundException {
- WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaName) + "/versions").queryParam("branch", schemaBranchName);
- return getEntities(webTarget, SchemaVersionInfo.class);
- }
-
- @Override
- public CompatibilityResult checkCompatibility(String schemaName, String toSchemaText) throws SchemaNotFoundException, SchemaBranchNotFoundException {
- return checkCompatibility(SchemaBranch.MASTER_BRANCH, schemaName, toSchemaText);
- }
-
- @Override
- public CompatibilityResult checkCompatibility(String schemaBranchName, String schemaName,
- String toSchemaText) throws SchemaNotFoundException {
- WebTarget webTarget = currentSchemaRegistryTargets().schemasTarget.path(encode(schemaName) + "/compatibility").queryParam("branch", schemaBranchName);
- String response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public String run() {
- return webTarget.request().post(Entity.text(toSchemaText), String.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- return readEntity(response, CompatibilityResult.class);
- }
-
- @Override
- public boolean isCompatibleWithAllVersions(String schemaName, String toSchemaText) throws SchemaNotFoundException, SchemaBranchNotFoundException {
- return isCompatibleWithAllVersions(SchemaBranch.MASTER_BRANCH, schemaName, toSchemaText);
- }
-
- @Override
- public boolean isCompatibleWithAllVersions(String schemaBranchName, String schemaName, String toSchemaText) throws SchemaNotFoundException, SchemaBranchNotFoundException {
- return checkCompatibility(schemaBranchName, schemaName, toSchemaText).isCompatible();
- }
-
- @Override
- public Collection findSchemasByFields(SchemaFieldQuery schemaFieldQuery) {
- WebTarget target = currentSchemaRegistryTargets().searchFieldsTarget;
- for (Map.Entry entry : schemaFieldQuery.toQueryMap().entrySet()) {
- target = target.queryParam(entry.getKey(), entry.getValue());
- }
-
- return getEntities(target, SchemaVersionKey.class);
- }
-
- @Override
- public String uploadFile(InputStream inputStream) {
- MultiPart multiPart = new MultiPart();
- BodyPart filePart = new StreamDataBodyPart("file", inputStream, "file");
- multiPart.bodyPart(filePart);
- try {
- return login.doAction(new PrivilegedAction() {
- @Override
- public String run() {
- return currentSchemaRegistryTargets().filesTarget.request()
- .post(Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA), String.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- }
-
- @Override
- public InputStream downloadFile(String fileId) {
- try {
- return login.doAction(new PrivilegedAction() {
- @Override
- public InputStream run() {
- return currentSchemaRegistryTargets().filesTarget.path("download/" + encode(fileId))
- .request()
- .get(InputStream.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- }
-
- @Override
- public Long addSerDes(SerDesPair serDesPair) {
- return postEntity(currentSchemaRegistryTargets().serializersTarget, serDesPair, Long.class);
- }
-
- @Override
- public void mapSchemaWithSerDes(String schemaName, Long serDesId) {
- String path = String.format("%s/mapping/%s", encode(schemaName), serDesId.toString());
-
- Boolean success = postEntity(currentSchemaRegistryTargets().schemasTarget.path(path), null, Boolean.class);
- LOG.info("Received response while mapping schema [{}] with serialzer/deserializer [{}] : [{}]", schemaName, serDesId, success);
- }
-
- @Override
- public T getDefaultSerializer(String type) throws SerDesException {
- Collection supportedSchemaProviders = getSupportedSchemaProviders();
- for (SchemaProviderInfo schemaProvider : supportedSchemaProviders) {
- if (schemaProvider.getType().equals(type)) {
- try {
- return (T) Class.forName(schemaProvider.getDefaultSerializerClassName()).newInstance();
- } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
- throw new SerDesException(e);
- }
- }
- }
-
- throw new IllegalArgumentException("No schema provider registered for the given type " + type);
- }
-
- @Override
- public T getDefaultDeserializer(String type) throws SerDesException {
- Collection supportedSchemaProviders = getSupportedSchemaProviders();
- for (SchemaProviderInfo schemaProvider : supportedSchemaProviders) {
- if (schemaProvider.getType().equals(type)) {
- try {
- return (T) Class.forName(schemaProvider.getDefaultDeserializerClassName()).newInstance();
- } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
- throw new SerDesException(e);
- }
- }
- }
-
- throw new IllegalArgumentException("No schema provider registered for the given type " + type);
- }
-
- @Override
- public Collection getSerDes(String schemaName) {
- String path = encode(schemaName) + "/serdes/";
- return getEntities(currentSchemaRegistryTargets().schemasTarget.path(path), SerDesInfo.class);
- }
-
- public T createSerializerInstance(SerDesInfo serDesInfo) {
- return createInstance(serDesInfo, true);
- }
-
- @Override
- public T createDeserializerInstance(SerDesInfo serDesInfo) {
- return createInstance(serDesInfo, false);
- }
-
- @Override
- public void close() {
- client.close();
- }
-
- public SchemaRegistryVersion clientVersion() {
- return CLIENT_VERSION;
- }
-
- private T createInstance(SerDesInfo serDesInfo, boolean isSerializer) {
- Set> interfaceClasses = isSerializer ? SERIALIZER_INTERFACE_CLASSES : DESERIALIZER_INTERFACE_CLASSES;
-
- if (interfaceClasses == null || interfaceClasses.isEmpty()) {
- throw new IllegalArgumentException("interfaceClasses array must be neither null nor empty.");
- }
-
- // loading serializer, create a class loader and and keep them in cache.
- final SerDesPair serDesPair = serDesInfo.getSerDesPair();
- String fileId = serDesPair.getFileId();
- // get class loader for this file ID
- ClassLoader classLoader = classLoaderCache.getClassLoader(fileId);
-
- T t;
- try {
- String className =
- isSerializer ? serDesPair.getSerializerClassName() : serDesPair.getDeserializerClassName();
-
- Class clazz = (Class) Class.forName(className, true, classLoader);
- t = clazz.newInstance();
- List> classes = new ArrayList<>();
- for (Class> interfaceClass : interfaceClasses) {
- if (interfaceClass.isAssignableFrom(clazz)) {
- classes.add(interfaceClass);
- }
- }
-
- if (classes.isEmpty()) {
- throw new RuntimeException("Given Serialize/Deserializer " + className + " class does not implement any " +
- "one of the registered interfaces: " + interfaceClasses);
- }
-
- Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
- classes.toArray(new Class[classes.size()]),
- new ClassLoaderAwareInvocationHandler(classLoader, t));
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- throw new SerDesException(e);
- }
-
- return t;
- }
-
- private List getEntities(WebTarget target, Class clazz) {
- String response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public String run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).get(String.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- return parseResponseAsEntities(response, clazz);
- }
-
- private List parseResponseAsEntities(String response, Class clazz) {
- List entities = new ArrayList<>();
- try {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode node = mapper.readTree(response);
- Iterator it = node.get("entities").elements();
- while (it.hasNext()) {
- entities.add(mapper.treeToValue(it.next(), clazz));
- }
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- return entities;
- }
-
- private T postEntity(WebTarget target, Object json, Class responseType) {
- String response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public String run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(json), String.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
- return readEntity(response, responseType);
- }
-
- private T readEntity(String response, Class clazz) {
- try {
- ObjectMapper mapper = new ObjectMapper();
- return mapper.readValue(response, clazz);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
- }
-
- private T getEntity(WebTarget target, Class clazz) {
- String response = null;
- try {
- response = login.doAction(new PrivilegedAction() {
- @Override
- public String run() {
- return target.request(MediaType.APPLICATION_JSON_TYPE).get(String.class);
- }
- });
- } catch (LoginException e) {
- throw new RegistryRetryableException(e);
- }
-
- return readEntity(response, clazz);
- }
-
- public static final class Configuration {
- // we may want to remove schema.registry prefix from configuration properties as these are all properties
- // given by client.
- /**
- * URL of schema registry to which this client connects to. For ex: http://localhost:9090/api/v1
- */
- public static final ConfigEntry SCHEMA_REGISTRY_URL =
- ConfigEntry.mandatory("schema.registry.url",
- String.class,
- "URL of schema registry to which this client connects to. For ex: http://localhost:9090/api/v1",
- "http://localhost:9090/api/v1",
- ConfigEntry.StringConverter.get(),
- ConfigEntry.NonEmptyStringValidator.get());
-
- /**
- * Default path for downloaded jars to be stored.
- */
- public static final String DEFAULT_LOCAL_JARS_PATH = "/tmp/schema-registry/local-jars";
-
- /**
- * Local directory path to which downloaded jars should be copied to. For ex: /tmp/schema-registry/local-jars
- */
- public static final ConfigEntry LOCAL_JAR_PATH =
- ConfigEntry.optional("schema.registry.client.local.jars.path",
- String.class,
- "URL of schema registry to which this client connects to. For ex: http://localhost:9090/api/v1",
- DEFAULT_LOCAL_JARS_PATH,
- ConfigEntry.StringConverter.get(),
- ConfigEntry.NonEmptyStringValidator.get());
-
- /**
- * Default value for classloader cache size.
- */
- public static final long DEFAULT_CLASSLOADER_CACHE_SIZE = 1024L;
-
- /**
- * Default value for cache expiry interval in seconds.
- */
- public static final long DEFAULT_CLASSLOADER_CACHE_EXPIRY_INTERVAL_SECS = 60 * 60L;
-
- /**
- * Maximum size of classloader cache. Default value is {@link #DEFAULT_CLASSLOADER_CACHE_SIZE}
- * Classloaders are created for serializer/deserializer jars downloaded from schema registry and they will be locally cached.
- */
- public static final ConfigEntry CLASSLOADER_CACHE_SIZE =
- ConfigEntry.optional("schema.registry.client.class.loader.cache.size",
- Integer.class,
- "Maximum size of classloader cache",
- DEFAULT_CLASSLOADER_CACHE_SIZE,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Expiry interval(in seconds) of an entry in classloader cache. Default value is {@link #DEFAULT_CLASSLOADER_CACHE_EXPIRY_INTERVAL_SECS}
- * Classloaders are created for serializer/deserializer jars downloaded from schema registry and they will be locally cached.
- */
- public static final ConfigEntry CLASSLOADER_CACHE_EXPIRY_INTERVAL_SECS =
- ConfigEntry.optional("schema.registry.client.class.loader.cache.expiry.interval.secs",
- Integer.class,
- "Expiry interval(in seconds) of an entry in classloader cache",
- DEFAULT_CLASSLOADER_CACHE_EXPIRY_INTERVAL_SECS,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- public static final long DEFAULT_SCHEMA_CACHE_SIZE = 1024;
- public static final long DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS = 5 * 60L;
-
- /**
- * Maximum size of schema version cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_SIZE}
- */
- public static final ConfigEntry SCHEMA_VERSION_CACHE_SIZE =
- ConfigEntry.optional("schema.registry.client.schema.version.cache.size",
- Integer.class,
- "Maximum size of schema version cache",
- DEFAULT_SCHEMA_CACHE_SIZE,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Expiry interval(in seconds) of an entry in schema version cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS}
- */
- public static final ConfigEntry SCHEMA_VERSION_CACHE_EXPIRY_INTERVAL_SECS =
- ConfigEntry.optional("schema.registry.client.schema.version.cache.expiry.interval.secs",
- Integer.class,
- "Expiry interval(in seconds) of an entry in schema version cache",
- DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Maximum size of schema metadata cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_SIZE}
- */
- public static final ConfigEntry SCHEMA_METADATA_CACHE_SIZE =
- ConfigEntry.optional("schema.registry.client.schema.metadata.cache.size",
- Integer.class,
- "Maximum size of schema metadata cache",
- DEFAULT_SCHEMA_CACHE_SIZE,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Expiry interval(in seconds) of an entry in schema metadata cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS}
- */
- public static final ConfigEntry SCHEMA_METADATA_CACHE_EXPIRY_INTERVAL_SECS =
- ConfigEntry.optional("schema.registry.client.schema.metadata.cache.expiry.interval.secs",
- Integer.class,
- "Expiry interval(in seconds) of an entry in schema metadata cache",
- DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Maximum size of schema text cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_SIZE}.
- * This cache has ability to store/get entries with same schema name and schema text.
- */
- public static final ConfigEntry SCHEMA_TEXT_CACHE_SIZE =
- ConfigEntry.optional("schema.registry.client.schema.text.cache.size",
- Integer.class,
- "Maximum size of schema text cache",
- DEFAULT_SCHEMA_CACHE_SIZE,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- * Expiry interval(in seconds) of an entry in schema text cache. Default value is {@link #DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS}
- */
- public static final ConfigEntry SCHEMA_TEXT_CACHE_EXPIRY_INTERVAL_SECS =
- ConfigEntry.optional("schema.registry.client.schema.text.cache.expiry.interval.secs",
- Integer.class,
- "Expiry interval(in seconds) of an entry in schema text cache.",
- DEFAULT_SCHEMA_CACHE_EXPIRY_INTERVAL_SECS,
- ConfigEntry.IntegerConverter.get(),
- ConfigEntry.PositiveNumberValidator.get());
-
- /**
- *
- */
- public static final ConfigEntry URL_SELECTOR_CLASS =
- ConfigEntry.optional("schema.registry.client.url.selector",
- String.class,
- "Schema Registry URL selector class.",
- FailoverUrlSelector.class.getName(),
- ConfigEntry.StringConverter.get(),
- ConfigEntry.NonEmptyStringValidator.get());
-
- /**
- *
- */
- public static final ConfigEntry SASL_JAAS_CONFIG =
- ConfigEntry.optional( "sasl.jaas.config",
- String.class,
- "Schema Registry Dynamic JAAS config for SASL connection.",
- null,
- ConfigEntry.StringConverter.get(),
- ConfigEntry.NonEmptyStringValidator.get());
-
- // connection properties
- /**
- * Default connection timeout on connections created while connecting to schema registry.
- */
- public static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000;
-
- /**
- * Default read timeout on connections created while connecting to schema registry.
- */
- public static final int DEFAULT_READ_TIMEOUT = 30 * 1000;
-
- private final Map config;
- private final Map> options;
-
- public Configuration(Map config) {
- Field[] fields = this.getClass().getDeclaredFields();
- this.options = Collections.unmodifiableMap(buildOptions(fields));
- this.config = buildConfig(config);
- }
-
- private Map buildConfig(Map config) {
- Map result = new HashMap<>();
- for (Map.Entry entry : config.entrySet()) {
- String key = entry.getKey();
- Object value = entry.getValue();
-
- ConfigEntry configEntry = options.get(key);
- if (configEntry != null) {
- if (value != null) {
- configEntry.validator().validate((value));
- } else {
- value = configEntry.defaultValue();
- }
- }
- result.put(key, value);
- }
-
- return result;
- }
-
- private Map> buildOptions(Field[] fields) {
- Map> options = new HashMap<>();
- for (Field field : fields) {
- Class> type = field.getType();
-
- if (type.isAssignableFrom(ConfigEntry.class)) {
- field.setAccessible(true);
- try {
- ConfigEntry configEntry = (ConfigEntry) field.get(this);
- options.put(configEntry.name(), configEntry);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return options;
- }
-
- public T getValue(String propertyKey) {
- return (T) (config.containsKey(propertyKey) ? config.get(propertyKey)
- : options.get(propertyKey).defaultValue());
- }
-
- public Map getConfig() {
- return Collections.unmodifiableMap(config);
- }
-
- public Collection> getAvailableConfigEntries() {
- return options.values();
- }
-
- }
-
- private static class SchemaDigestEntry {
- private final String name;
- private final byte[] schemaDigest;
-
- SchemaDigestEntry(String name, byte[] schemaDigest) {
- Objects.requireNonNull(name, "name can not be null");
- Objects.requireNonNull(schemaDigest, "schema digest can not be null");
-
- this.name = name;
- this.schemaDigest = schemaDigest;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- SchemaDigestEntry that = (SchemaDigestEntry) o;
-
- if (name != null ? !name.equals(that.name) : that.name != null) return false;
- return Arrays.equals(schemaDigest, that.schemaDigest);
-
- }
-
- @Override
- public int hashCode() {
- int result = name != null ? name.hashCode() : 0;
- result = 31 * result + Arrays.hashCode(schemaDigest);
- return result;
- }
- }
-}
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistry.java b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistry.java
index bd3a1a084d..a6a03cdc61 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistry.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistry.java
@@ -76,55 +76,55 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
private static final String CLIENT_SSL_PROPERTY_PREFIX = "schema.registry.client.ssl";
private final ConcurrentMap, RecordSchema> schemaNameToSchemaMap = new ConcurrentHashMap<>();
- private final ConcurrentMap, Tuple> schemaVersionByNameCache = new ConcurrentHashMap<>();
+ private final ConcurrentMap, Tuple> schemaVersionByNameCache = new ConcurrentHashMap<>();
private final ConcurrentMap> schemaVersionByKeyCache = new ConcurrentHashMap<>();
private volatile long versionInfoCacheNanos;
static final PropertyDescriptor URL = new PropertyDescriptor.Builder()
- .name("url")
- .displayName("Schema Registry URL")
- .description("URL of the schema registry that this Controller Service should connect to, including version. For example, http://localhost:9090/api/v1")
- .addValidator(StandardValidators.URL_VALIDATOR)
- .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
- .required(true)
- .build();
+ .name("url")
+ .displayName("Schema Registry URL")
+ .description("URL of the schema registry that this Controller Service should connect to, including version. For example, http://localhost:9090/api/v1")
+ .addValidator(StandardValidators.URL_VALIDATOR)
+ .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+ .required(true)
+ .build();
static final PropertyDescriptor CACHE_SIZE = new PropertyDescriptor.Builder()
- .name("cache-size")
- .displayName("Cache Size")
- .description("Specifies how many Schemas should be cached from the Hortonworks Schema Registry")
- .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR)
- .defaultValue("1000")
- .required(true)
- .build();
+ .name("cache-size")
+ .displayName("Cache Size")
+ .description("Specifies how many Schemas should be cached from the Hortonworks Schema Registry")
+ .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR)
+ .defaultValue("1000")
+ .required(true)
+ .build();
static final PropertyDescriptor CACHE_EXPIRATION = new PropertyDescriptor.Builder()
- .name("cache-expiration")
- .displayName("Cache Expiration")
- .description("Specifies how long a Schema that is cached should remain in the cache. Once this time period elapses, a "
- + "cached version of a schema will no longer be used, and the service will have to communicate with the "
- + "Hortonworks Schema Registry again in order to obtain the schema.")
- .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR)
- .defaultValue("1 hour")
- .required(true)
- .build();
+ .name("cache-expiration")
+ .displayName("Cache Expiration")
+ .description("Specifies how long a Schema that is cached should remain in the cache. Once this time period elapses, a "
+ + "cached version of a schema will no longer be used, and the service will have to communicate with the "
+ + "Hortonworks Schema Registry again in order to obtain the schema.")
+ .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR)
+ .defaultValue("1 hour")
+ .required(true)
+ .build();
static final PropertyDescriptor SSL_CONTEXT_SERVICE = new PropertyDescriptor.Builder()
- .name("ssl-context-service")
- .displayName("SSL Context Service")
- .description("Specifies the SSL Context Service to use for communicating with Schema Registry.")
- .required(false)
- .identifiesControllerService(SSLContextService.class)
- .build();
+ .name("ssl-context-service")
+ .displayName("SSL Context Service")
+ .description("Specifies the SSL Context Service to use for communicating with Schema Registry.")
+ .required(false)
+ .identifiesControllerService(SSLContextService.class)
+ .build();
static final PropertyDescriptor KERBEROS_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder()
- .name("kerberos-credentials-service")
- .displayName("Kerberos Credentials Service")
- .description("Specifies the Kerberos Credentials Controller Service that should be used for authenticating with Kerberos")
- .identifiesControllerService(KerberosCredentialsService.class)
- .required(false)
- .build();
+ .name("kerberos-credentials-service")
+ .displayName("Kerberos Credentials Service")
+ .description("Specifies the Kerberos Credentials Controller Service that should be used for authenticating with Kerberos")
+ .identifiesControllerService(KerberosCredentialsService.class)
+ .required(false)
+ .build();
static final PropertyDescriptor KERBEROS_PRINCIPAL = new PropertyDescriptor.Builder()
.name("kerberos-principal")
@@ -145,6 +145,23 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.build();
+ static final PropertyDescriptor BASIC_AUTH_USERNAME = new PropertyDescriptor.Builder()
+ .name("basic-auth-username")
+ .displayName("Basic Authentication Username")
+ .description("The username to use for basic authentication when the Schema Registry is behind a proxy such as Apache Knox.")
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .dependsOn(SSL_CONTEXT_SERVICE)
+ .build();
+
+ static final PropertyDescriptor BASIC_AUTH_PASSWORD = new PropertyDescriptor.Builder()
+ .name("basic-auth-password")
+ .displayName("Basic Authentication Password")
+ .description("The password to use for basic authentication when the Schema Registry is behind a proxy such as Apache Knox.")
+ .sensitive(true)
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .dependsOn(SSL_CONTEXT_SERVICE)
+ .build();
+
private volatile boolean usingKerberosWithPassword = false;
private volatile SchemaRegistryClient schemaRegistryClient;
private volatile boolean initialized;
@@ -157,6 +174,8 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
final String kerberosPrincipal = validationContext.getProperty(KERBEROS_PRINCIPAL).evaluateAttributeExpressions().getValue();
final String kerberosPassword = validationContext.getProperty(KERBEROS_PASSWORD).getValue();
+ final String basicAuthUsername = validationContext.getProperty(BASIC_AUTH_USERNAME).evaluateAttributeExpressions().getValue();
+
final KerberosCredentialsService kerberosCredentialsService = validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE)
.asControllerService(KerberosCredentialsService.class);
@@ -184,6 +203,23 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
.build());
}
+ if ((validationContext.getProperty(BASIC_AUTH_USERNAME).isSet() || validationContext.getProperty(BASIC_AUTH_PASSWORD).isSet())
+ && !validationContext.getProperty(SSL_CONTEXT_SERVICE).isSet()) {
+ results.add(new ValidationResult.Builder()
+ .subject(BASIC_AUTH_USERNAME.getDisplayName())
+ .valid(false)
+ .explanation("SSL Context Service must be set when using basic authentication")
+ .build());
+ }
+
+ if ((!StringUtils.isBlank(kerberosPrincipal) || kerberosCredentialsService != null ) && !StringUtils.isBlank(basicAuthUsername)) {
+ results.add(new ValidationResult.Builder()
+ .subject(BASIC_AUTH_USERNAME.getDisplayName())
+ .valid(false)
+ .explanation("kerberos- and basic authentication cannot be configured at the same time")
+ .build());
+ }
+
return results;
}
@@ -229,6 +265,14 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
schemaRegistryConfig.put(SchemaRegistryClientWithKerberosPassword.SCHEMA_REGISTRY_CLIENT_NIFI_COMP_LOGGER, getLogger());
usingKerberosWithPassword = true;
}
+
+ if (context.getProperty(BASIC_AUTH_USERNAME).isSet()) {
+ schemaRegistryConfig.put(SchemaRegistryClient.Configuration.AUTH_USERNAME.name(), context.getProperty(BASIC_AUTH_USERNAME).getValue());
+ }
+
+ if (context.getProperty(BASIC_AUTH_PASSWORD).isSet()) {
+ schemaRegistryConfig.put(SchemaRegistryClient.Configuration.AUTH_PASSWORD.name(), context.getProperty(BASIC_AUTH_PASSWORD).getValue());
+ }
}
private String getKeytabJaasConfig(final String principal, final String keytab) {
@@ -259,7 +303,7 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
propertiesBuilder.put("trustStoreType", sslContextService.getTrustStoreType());
}
}
- return Collections.unmodifiableMap(propertiesBuilder);
+ return Collections.unmodifiableMap(propertiesBuilder);
}
@OnDisabled
@@ -283,6 +327,8 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
properties.add(KERBEROS_CREDENTIALS_SERVICE);
properties.add(KERBEROS_PRINCIPAL);
properties.add(KERBEROS_PASSWORD);
+ properties.add(BASIC_AUTH_USERNAME);
+ properties.add(BASIC_AUTH_PASSWORD);
return properties;
}
@@ -304,7 +350,7 @@ public class HortonworksSchemaRegistry extends AbstractControllerService impleme
throws org.apache.nifi.schema.access.SchemaNotFoundException {
try {
// Try to fetch the SchemaVersionInfo from the cache.
- final Tuple nameAndBranch = new Tuple<>(schemaName, branchName);
+ final Tuple nameAndBranch = new Tuple<>(schemaName, branchName);
final Tuple timestampedVersionInfo = schemaVersionByNameCache.get(nameAndBranch);
// Determine if the timestampedVersionInfo is expired
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
index 18eb77c277..af644a24ff 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/main/java/org/apache/nifi/schemaregistry/hortonworks/SchemaRegistryClientWithKerberosPassword.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.schemaregistry.hortonworks;
+import com.hortonworks.registries.auth.Login;
import com.hortonworks.registries.schemaregistry.client.SchemaRegistryClient;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.security.krb.KerberosLoginException;
@@ -25,6 +26,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.login.LoginException;
+import java.lang.reflect.Field;
import java.util.Map;
/**
@@ -47,17 +49,17 @@ public class SchemaRegistryClientWithKerberosPassword extends SchemaRegistryClie
@Override
protected void initializeSecurityContext() {
- final String principal = configuration.getValue(SCHEMA_REGISTRY_CLIENT_KERBEROS_PRINCIPAL);
+ final String principal = getConfiguration().getValue(SCHEMA_REGISTRY_CLIENT_KERBEROS_PRINCIPAL);
if (principal == null) {
throw new IllegalArgumentException("Failed to login because principal is null");
}
- final String password = configuration.getValue(SCHEMA_REGISTRY_CLIENT_KERBEROS_PASSWORD);
+ final String password = getConfiguration().getValue(SCHEMA_REGISTRY_CLIENT_KERBEROS_PASSWORD);
if (password == null) {
throw new IllegalArgumentException("Failed to login because password is null");
}
- final Object loggerObject = configuration.getValue(SCHEMA_REGISTRY_CLIENT_NIFI_COMP_LOGGER);
+ final Object loggerObject = getConfiguration().getValue(SCHEMA_REGISTRY_CLIENT_NIFI_COMP_LOGGER);
if (loggerObject == null) {
throw new IllegalArgumentException("Failed to login because component logger is required");
}
@@ -67,7 +69,8 @@ public class SchemaRegistryClientWithKerberosPassword extends SchemaRegistryClie
}
kerberosUser = new KerberosPasswordUser(principal, password);
- login = new KerberosUserLogin(kerberosUser, (ComponentLog) loggerObject);
+ Login login = new KerberosUserLogin(kerberosUser, (ComponentLog) loggerObject);
+ setLogin(login);
try {
login.login();
@@ -76,6 +79,16 @@ public class SchemaRegistryClientWithKerberosPassword extends SchemaRegistryClie
}
}
+ public void setLogin(Login login) {
+ try {
+ Field loginField = SchemaRegistryClient.class.getDeclaredField("login");
+ loginField.setAccessible(true);
+ loginField.set(this, login);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public void close() {
try {
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/test/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistryTest.java b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/test/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistryTest.java
new file mode 100644
index 0000000000..8954b9e620
--- /dev/null
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-hwx-schema-registry-bundle/nifi-hwx-schema-registry-service/src/test/java/org/apache/nifi/schemaregistry/hortonworks/HortonworksSchemaRegistryTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.schemaregistry.hortonworks;
+
+import org.apache.nifi.controller.ControllerService;
+import org.apache.nifi.kerberos.KerberosCredentialsService;
+import org.apache.nifi.processor.Processor;
+import org.apache.nifi.reporting.InitializationException;
+import org.apache.nifi.ssl.SSLContextService;
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.when;
+
+public class HortonworksSchemaRegistryTest {
+ private HortonworksSchemaRegistry testSubject;
+
+ private TestRunner runner;
+
+ @Mock
+ private Processor dummyProcessor;
+ @Mock
+ private SSLContextService mockSSLContextService;
+ @Mock
+ private KerberosCredentialsService mockKerberosCredentialsService;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ MockitoAnnotations.openMocks(this);
+
+ testSubject = new HortonworksSchemaRegistry();
+
+ runner = TestRunners.newTestRunner(dummyProcessor);
+ runner.addControllerService("hortonworks-schema-registry", testSubject);
+
+ when(mockSSLContextService.getIdentifier()).thenReturn("ssl-controller-service-id");
+ when(mockKerberosCredentialsService.getIdentifier()).thenReturn("kerberos-credentials-service-id");
+ }
+
+ @Test
+ void invalidWhenBasicUsernameWithoutSSLContextIsSet() throws Exception {
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.URL, "http://unimportant");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.BASIC_AUTH_USERNAME, "username");
+
+ runner.assertNotValid(testSubject);
+ }
+
+ @Test
+ void validWhenBasicUsernameWithSSLContextIsSet() throws Exception {
+ addAndEnable(mockSSLContextService);
+
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.URL, "http://unimportant");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.SSL_CONTEXT_SERVICE, mockSSLContextService.getIdentifier());
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.BASIC_AUTH_USERNAME, "basic username");
+
+ runner.assertValid(testSubject);
+ }
+
+ @Test
+ void invalidWhenBasicUsernameAndKerberosPrincipalBothSet() throws Exception {
+ addAndEnable(mockSSLContextService);
+
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.URL, "http://unimportant");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.SSL_CONTEXT_SERVICE, mockSSLContextService.getIdentifier());
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.BASIC_AUTH_USERNAME, "basic username");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.KERBEROS_PRINCIPAL, "kerberos principal");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.KERBEROS_PASSWORD, "kerberos password");
+
+ runner.assertNotValid(testSubject);
+ }
+
+ @Test
+ void invalidWhenBasicUsernameAndKerberosCredentialsServivceBothSet() throws Exception {
+ addAndEnable(mockSSLContextService);
+ addAndEnable(mockKerberosCredentialsService);
+
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.URL, "http://unimportant");
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.SSL_CONTEXT_SERVICE, mockSSLContextService.getIdentifier());
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.KERBEROS_CREDENTIALS_SERVICE, mockKerberosCredentialsService.getIdentifier());
+ runner.setProperty(testSubject, HortonworksSchemaRegistry.BASIC_AUTH_USERNAME, "basic username");
+
+ runner.assertNotValid(testSubject);
+ }
+
+ private void addAndEnable(ControllerService service) throws InitializationException {
+ runner.addControllerService(service.getIdentifier(), service);
+ runner.enableControllerService(service);
+ }
+}