From c2048105a19716b8af299066a035248384a7ac16 Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Fri, 17 Jul 2026 12:34:12 +0200 Subject: [PATCH 1/4] Add camel-apicurio-registry component New Camel component wrapping the Apicurio Registry v3 REST API via the apicurio-registry-java-sdk. Assisted by Claude, model: claude-opus-4-6 --- catalog/camel-allcomponents/pom.xml | 5 + components/camel-apicurio-registry/pom.xml | 86 ++++++ .../ApicurioRegistryComponentConfigurer.java | 145 ++++++++++ .../ApicurioRegistryEndpointConfigurer.java | 243 +++++++++++++++++ .../ApicurioRegistryEndpointUriFactory.java | 121 +++++++++ ...RegistryProducerInvokeOnHeaderFactory.java | 46 ++++ .../apicurioregistry/apicurio-registry.json | 102 ++++++++ .../org/apache/camel/component.properties | 7 + .../apache/camel/component/apicurio-registry | 2 + .../configurer/apicurio-registry-component | 2 + .../configurer/apicurio-registry-endpoint | 2 + ....apicurioregistry.ApicurioRegistryProducer | 2 + .../urifactory/apicurio-registry-endpoint | 2 + .../docs/apicurio-registry-component.adoc | 198 ++++++++++++++ .../ApicurioRegistryComponent.java | 66 +++++ .../ApicurioRegistryConfiguration.java | 201 ++++++++++++++ .../ApicurioRegistryConstants.java | 79 ++++++ .../ApicurioRegistryConsumer.java | 99 +++++++ .../ApicurioRegistryEndpoint.java | 132 ++++++++++ .../ApicurioRegistryProducer.java | 247 ++++++++++++++++++ .../ApicurioRegistryValidationException.java | 33 +++ .../ApicurioRegistryComponentTest.java | 89 +++++++ .../ApicurioRegistryConsumerTest.java | 112 ++++++++ .../ApicurioRegistryProducerTest.java | 209 +++++++++++++++ .../ApicurioRegistryConsumerIT.java | 95 +++++++ .../ApicurioRegistryProducerIT.java | 212 +++++++++++++++ .../ApicurioRegistryTestSupport.java | 41 +++ .../ApicurioRegistryValidateIT.java | 132 ++++++++++ components/pom.xml | 1 + parent/pom.xml | 5 + .../pom.xml | 41 +++ .../common/ApicurioRegistryProperties.java | 28 ++ .../ApicurioRegistryInfraService.java | 28 ++ ...rioRegistryLocalContainerInfraService.java | 104 ++++++++ .../ApicurioRegistryRemoteInfraService.java | 58 ++++ .../services/ApicurioRegistryService.java | 23 ++ .../ApicurioRegistryServiceFactory.java | 46 ++++ .../registry/services/container.properties | 17 ++ test-infra/pom.xml | 1 + 39 files changed, 3062 insertions(+) create mode 100644 components/camel-apicurio-registry/pom.xml create mode 100644 components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java create mode 100644 components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java create mode 100644 components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java create mode 100644 components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerInvokeOnHeaderFactory.java create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component.properties create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component/apicurio-registry create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-component create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-endpoint create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/invoke-on-header/org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer create mode 100644 components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/urifactory/apicurio-registry-endpoint create mode 100644 components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponent.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpoint.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java create mode 100644 components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryValidationException.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentTest.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryTestSupport.java create mode 100644 components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/pom.xml create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/common/ApicurioRegistryProperties.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryInfraService.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryRemoteInfraService.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryService.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryServiceFactory.java create mode 100644 test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index 1a90dfd62cd20..4a53af65bf282 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -77,6 +77,11 @@ camel-amqp ${project.version} + + org.apache.camel + camel-apicurio-registry + ${project.version} + org.apache.camel camel-arangodb diff --git a/components/camel-apicurio-registry/pom.xml b/components/camel-apicurio-registry/pom.xml new file mode 100644 index 0000000000000..6745134f6042c --- /dev/null +++ b/components/camel-apicurio-registry/pom.xml @@ -0,0 +1,86 @@ + + + + + 4.0.0 + + + components + org.apache.camel + 4.22.0-SNAPSHOT + + + camel-apicurio-registry + jar + + Camel :: Apicurio Registry + Camel Apicurio Registry component + + + 3.3.0 + + + + + + org.apache.camel + camel-support + + + + + io.apicurio + apicurio-registry-java-sdk + ${apicurio-registry-sdk-version} + + + + + org.apache.camel + camel-test-junit5 + test + + + org.apache.camel + camel-direct + test + + + org.apache.camel + camel-mock + test + + + org.mockito + mockito-core + ${mockito-version} + test + + + + + org.apache.camel + camel-test-infra-apicurio-registry + ${project.version} + test + + + + diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java new file mode 100644 index 0000000000000..4f83f5274502f --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java @@ -0,0 +1,145 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.apicurioregistry; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class ApicurioRegistryComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + private org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration getOrCreateConfiguration(ApicurioRegistryComponent target) { + if (target.getConfiguration() == null) { + target.setConfiguration(new org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration()); + } + return target.getConfiguration(); + } + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + ApicurioRegistryComponent target = (ApicurioRegistryComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": getOrCreateConfiguration(target).setArtifactType(property(camelContext, java.lang.String.class, value)); return true; + case "authtype": + case "authType": getOrCreateConfiguration(target).setAuthType(property(camelContext, java.lang.String.class, value)); return true; + case "autowiredenabled": + case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "cachettl": + case "cacheTtl": getOrCreateConfiguration(target).setCacheTtl(property(camelContext, long.class, value)); return true; + case "clientid": + case "clientId": getOrCreateConfiguration(target).setClientId(property(camelContext, java.lang.String.class, value)); return true; + case "clientsecret": + case "clientSecret": getOrCreateConfiguration(target).setClientSecret(property(camelContext, java.lang.String.class, value)); return true; + case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration.class, value)); return true; + case "failonvalidation": + case "failOnValidation": getOrCreateConfiguration(target).setFailOnValidation(property(camelContext, boolean.class, value)); return true; + case "fetchcontent": + case "fetchContent": getOrCreateConfiguration(target).setFetchContent(property(camelContext, boolean.class, value)); return true; + case "ifexists": + case "ifExists": getOrCreateConfiguration(target).setIfExists(property(camelContext, java.lang.String.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "operation": getOrCreateConfiguration(target).setOperation(property(camelContext, java.lang.String.class, value)); return true; + case "password": getOrCreateConfiguration(target).setPassword(property(camelContext, java.lang.String.class, value)); return true; + case "registryurl": + case "registryUrl": getOrCreateConfiguration(target).setRegistryUrl(property(camelContext, java.lang.String.class, value)); return true; + case "scope": getOrCreateConfiguration(target).setScope(property(camelContext, java.lang.String.class, value)); return true; + case "tokenendpoint": + case "tokenEndpoint": getOrCreateConfiguration(target).setTokenEndpoint(property(camelContext, java.lang.String.class, value)); return true; + case "username": getOrCreateConfiguration(target).setUsername(property(camelContext, java.lang.String.class, value)); return true; + default: return false; + } + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": return java.lang.String.class; + case "authtype": + case "authType": return java.lang.String.class; + case "autowiredenabled": + case "autowiredEnabled": return boolean.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "cachettl": + case "cacheTtl": return long.class; + case "clientid": + case "clientId": return java.lang.String.class; + case "clientsecret": + case "clientSecret": return java.lang.String.class; + case "configuration": return org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration.class; + case "failonvalidation": + case "failOnValidation": return boolean.class; + case "fetchcontent": + case "fetchContent": return boolean.class; + case "ifexists": + case "ifExists": return java.lang.String.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + case "operation": return java.lang.String.class; + case "password": return java.lang.String.class; + case "registryurl": + case "registryUrl": return java.lang.String.class; + case "scope": return java.lang.String.class; + case "tokenendpoint": + case "tokenEndpoint": return java.lang.String.class; + case "username": return java.lang.String.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + ApicurioRegistryComponent target = (ApicurioRegistryComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": return getOrCreateConfiguration(target).getArtifactType(); + case "authtype": + case "authType": return getOrCreateConfiguration(target).getAuthType(); + case "autowiredenabled": + case "autowiredEnabled": return target.isAutowiredEnabled(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "cachettl": + case "cacheTtl": return getOrCreateConfiguration(target).getCacheTtl(); + case "clientid": + case "clientId": return getOrCreateConfiguration(target).getClientId(); + case "clientsecret": + case "clientSecret": return getOrCreateConfiguration(target).getClientSecret(); + case "configuration": return target.getConfiguration(); + case "failonvalidation": + case "failOnValidation": return getOrCreateConfiguration(target).isFailOnValidation(); + case "fetchcontent": + case "fetchContent": return getOrCreateConfiguration(target).isFetchContent(); + case "ifexists": + case "ifExists": return getOrCreateConfiguration(target).getIfExists(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + case "operation": return getOrCreateConfiguration(target).getOperation(); + case "password": return getOrCreateConfiguration(target).getPassword(); + case "registryurl": + case "registryUrl": return getOrCreateConfiguration(target).getRegistryUrl(); + case "scope": return getOrCreateConfiguration(target).getScope(); + case "tokenendpoint": + case "tokenEndpoint": return getOrCreateConfiguration(target).getTokenEndpoint(); + case "username": return getOrCreateConfiguration(target).getUsername(); + default: return null; + } + } +} + diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java new file mode 100644 index 0000000000000..e4916994a870b --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java @@ -0,0 +1,243 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.apicurioregistry; + +import javax.annotation.processing.Generated; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.EndpointSchemaGeneratorMojo") +@SuppressWarnings("unchecked") +public class ApicurioRegistryEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + ApicurioRegistryEndpoint target = (ApicurioRegistryEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": target.getConfiguration().setArtifactType(property(camelContext, java.lang.String.class, value)); return true; + case "authtype": + case "authType": target.getConfiguration().setAuthType(property(camelContext, java.lang.String.class, value)); return true; + case "backofferrorthreshold": + case "backoffErrorThreshold": target.setBackoffErrorThreshold(property(camelContext, int.class, value)); return true; + case "backoffidlethreshold": + case "backoffIdleThreshold": target.setBackoffIdleThreshold(property(camelContext, int.class, value)); return true; + case "backoffmultiplier": + case "backoffMultiplier": target.setBackoffMultiplier(property(camelContext, int.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "cachettl": + case "cacheTtl": target.getConfiguration().setCacheTtl(property(camelContext, long.class, value)); return true; + case "clientid": + case "clientId": target.getConfiguration().setClientId(property(camelContext, java.lang.String.class, value)); return true; + case "clientsecret": + case "clientSecret": target.getConfiguration().setClientSecret(property(camelContext, java.lang.String.class, value)); return true; + case "delay": target.setDelay(property(camelContext, long.class, value)); return true; + case "exceptionhandler": + case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true; + case "exchangepattern": + case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true; + case "failonvalidation": + case "failOnValidation": target.getConfiguration().setFailOnValidation(property(camelContext, boolean.class, value)); return true; + case "fetchcontent": + case "fetchContent": target.getConfiguration().setFetchContent(property(camelContext, boolean.class, value)); return true; + case "greedy": target.setGreedy(property(camelContext, boolean.class, value)); return true; + case "ifexists": + case "ifExists": target.getConfiguration().setIfExists(property(camelContext, java.lang.String.class, value)); return true; + case "initialdelay": + case "initialDelay": target.setInitialDelay(property(camelContext, long.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "operation": target.getConfiguration().setOperation(property(camelContext, java.lang.String.class, value)); return true; + case "password": target.getConfiguration().setPassword(property(camelContext, java.lang.String.class, value)); return true; + case "pollstrategy": + case "pollStrategy": target.setPollStrategy(property(camelContext, org.apache.camel.spi.PollingConsumerPollStrategy.class, value)); return true; + case "registryclient": + case "registryClient": target.setRegistryClient(property(camelContext, io.apicurio.registry.rest.client.RegistryClient.class, value)); return true; + case "registryurl": + case "registryUrl": target.getConfiguration().setRegistryUrl(property(camelContext, java.lang.String.class, value)); return true; + case "repeatcount": + case "repeatCount": target.setRepeatCount(property(camelContext, long.class, value)); return true; + case "runlogginglevel": + case "runLoggingLevel": target.setRunLoggingLevel(property(camelContext, org.apache.camel.LoggingLevel.class, value)); return true; + case "scheduledexecutorservice": + case "scheduledExecutorService": target.setScheduledExecutorService(property(camelContext, java.util.concurrent.ScheduledExecutorService.class, value)); return true; + case "scheduler": target.setScheduler(property(camelContext, java.lang.Object.class, value)); return true; + case "schedulerproperties": + case "schedulerProperties": target.setSchedulerProperties(property(camelContext, java.util.Map.class, value)); return true; + case "scope": target.getConfiguration().setScope(property(camelContext, java.lang.String.class, value)); return true; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": target.setSendEmptyMessageWhenIdle(property(camelContext, boolean.class, value)); return true; + case "startscheduler": + case "startScheduler": target.setStartScheduler(property(camelContext, boolean.class, value)); return true; + case "timeunit": + case "timeUnit": target.setTimeUnit(property(camelContext, java.util.concurrent.TimeUnit.class, value)); return true; + case "tokenendpoint": + case "tokenEndpoint": target.getConfiguration().setTokenEndpoint(property(camelContext, java.lang.String.class, value)); return true; + case "usefixeddelay": + case "useFixedDelay": target.setUseFixedDelay(property(camelContext, boolean.class, value)); return true; + case "username": target.getConfiguration().setUsername(property(camelContext, java.lang.String.class, value)); return true; + default: return false; + } + } + + @Override + public Class getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": return java.lang.String.class; + case "authtype": + case "authType": return java.lang.String.class; + case "backofferrorthreshold": + case "backoffErrorThreshold": return int.class; + case "backoffidlethreshold": + case "backoffIdleThreshold": return int.class; + case "backoffmultiplier": + case "backoffMultiplier": return int.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "cachettl": + case "cacheTtl": return long.class; + case "clientid": + case "clientId": return java.lang.String.class; + case "clientsecret": + case "clientSecret": return java.lang.String.class; + case "delay": return long.class; + case "exceptionhandler": + case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class; + case "exchangepattern": + case "exchangePattern": return org.apache.camel.ExchangePattern.class; + case "failonvalidation": + case "failOnValidation": return boolean.class; + case "fetchcontent": + case "fetchContent": return boolean.class; + case "greedy": return boolean.class; + case "ifexists": + case "ifExists": return java.lang.String.class; + case "initialdelay": + case "initialDelay": return long.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + case "operation": return java.lang.String.class; + case "password": return java.lang.String.class; + case "pollstrategy": + case "pollStrategy": return org.apache.camel.spi.PollingConsumerPollStrategy.class; + case "registryclient": + case "registryClient": return io.apicurio.registry.rest.client.RegistryClient.class; + case "registryurl": + case "registryUrl": return java.lang.String.class; + case "repeatcount": + case "repeatCount": return long.class; + case "runlogginglevel": + case "runLoggingLevel": return org.apache.camel.LoggingLevel.class; + case "scheduledexecutorservice": + case "scheduledExecutorService": return java.util.concurrent.ScheduledExecutorService.class; + case "scheduler": return java.lang.Object.class; + case "schedulerproperties": + case "schedulerProperties": return java.util.Map.class; + case "scope": return java.lang.String.class; + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return boolean.class; + case "startscheduler": + case "startScheduler": return boolean.class; + case "timeunit": + case "timeUnit": return java.util.concurrent.TimeUnit.class; + case "tokenendpoint": + case "tokenEndpoint": return java.lang.String.class; + case "usefixeddelay": + case "useFixedDelay": return boolean.class; + case "username": return java.lang.String.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + ApicurioRegistryEndpoint target = (ApicurioRegistryEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "artifacttype": + case "artifactType": return target.getConfiguration().getArtifactType(); + case "authtype": + case "authType": return target.getConfiguration().getAuthType(); + case "backofferrorthreshold": + case "backoffErrorThreshold": return target.getBackoffErrorThreshold(); + case "backoffidlethreshold": + case "backoffIdleThreshold": return target.getBackoffIdleThreshold(); + case "backoffmultiplier": + case "backoffMultiplier": return target.getBackoffMultiplier(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "cachettl": + case "cacheTtl": return target.getConfiguration().getCacheTtl(); + case "clientid": + case "clientId": return target.getConfiguration().getClientId(); + case "clientsecret": + case "clientSecret": return target.getConfiguration().getClientSecret(); + case "delay": return target.getDelay(); + case "exceptionhandler": + case "exceptionHandler": return target.getExceptionHandler(); + case "exchangepattern": + case "exchangePattern": return target.getExchangePattern(); + case "failonvalidation": + case "failOnValidation": return target.getConfiguration().isFailOnValidation(); + case "fetchcontent": + case "fetchContent": return target.getConfiguration().isFetchContent(); + case "greedy": return target.isGreedy(); + case "ifexists": + case "ifExists": return target.getConfiguration().getIfExists(); + case "initialdelay": + case "initialDelay": return target.getInitialDelay(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + case "operation": return target.getConfiguration().getOperation(); + case "password": return target.getConfiguration().getPassword(); + case "pollstrategy": + case "pollStrategy": return target.getPollStrategy(); + case "registryclient": + case "registryClient": return target.getRegistryClient(); + case "registryurl": + case "registryUrl": return target.getConfiguration().getRegistryUrl(); + case "repeatcount": + case "repeatCount": return target.getRepeatCount(); + case "runlogginglevel": + case "runLoggingLevel": return target.getRunLoggingLevel(); + case "scheduledexecutorservice": + case "scheduledExecutorService": return target.getScheduledExecutorService(); + case "scheduler": return target.getScheduler(); + case "schedulerproperties": + case "schedulerProperties": return target.getSchedulerProperties(); + case "scope": return target.getConfiguration().getScope(); + case "sendemptymessagewhenidle": + case "sendEmptyMessageWhenIdle": return target.isSendEmptyMessageWhenIdle(); + case "startscheduler": + case "startScheduler": return target.isStartScheduler(); + case "timeunit": + case "timeUnit": return target.getTimeUnit(); + case "tokenendpoint": + case "tokenEndpoint": return target.getConfiguration().getTokenEndpoint(); + case "usefixeddelay": + case "useFixedDelay": return target.isUseFixedDelay(); + case "username": return target.getConfiguration().getUsername(); + default: return null; + } + } + + @Override + public Object getCollectionValueType(Object target, String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "schedulerproperties": + case "schedulerProperties": return java.lang.Object.class; + default: return null; + } + } +} + diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java new file mode 100644 index 0000000000000..90577aab7f31e --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java @@ -0,0 +1,121 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.apicurioregistry; + +import javax.annotation.processing.Generated; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.spi.EndpointUriFactory; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo") +public class ApicurioRegistryEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory { + + private static final String BASE = ":groupId/artifactId"; + + private static final Set PROPERTY_NAMES; + private static final Set SECRET_PROPERTY_NAMES; + private static final Set ENDPOINT_IDENTITY_PROPERTY_NAMES; + private static final Map MULTI_VALUE_PREFIXES; + static { + Set props = new HashSet<>(37); + props.add("artifactId"); + props.add("artifactType"); + props.add("authType"); + props.add("backoffErrorThreshold"); + props.add("backoffIdleThreshold"); + props.add("backoffMultiplier"); + props.add("bridgeErrorHandler"); + props.add("cacheTtl"); + props.add("clientId"); + props.add("clientSecret"); + props.add("delay"); + props.add("exceptionHandler"); + props.add("exchangePattern"); + props.add("failOnValidation"); + props.add("fetchContent"); + props.add("greedy"); + props.add("groupId"); + props.add("ifExists"); + props.add("initialDelay"); + props.add("lazyStartProducer"); + props.add("operation"); + props.add("password"); + props.add("pollStrategy"); + props.add("registryClient"); + props.add("registryUrl"); + props.add("repeatCount"); + props.add("runLoggingLevel"); + props.add("scheduledExecutorService"); + props.add("scheduler"); + props.add("schedulerProperties"); + props.add("scope"); + props.add("sendEmptyMessageWhenIdle"); + props.add("startScheduler"); + props.add("timeUnit"); + props.add("tokenEndpoint"); + props.add("useFixedDelay"); + props.add("username"); + PROPERTY_NAMES = Collections.unmodifiableSet(props); + Set secretProps = new HashSet<>(4); + secretProps.add("clientId"); + secretProps.add("clientSecret"); + secretProps.add("password"); + secretProps.add("username"); + SECRET_PROPERTY_NAMES = Collections.unmodifiableSet(secretProps); + ENDPOINT_IDENTITY_PROPERTY_NAMES = Collections.emptySet(); + Map prefixes = new HashMap<>(1); + prefixes.put("schedulerProperties", "scheduler."); + MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes); + } + + @Override + public boolean isEnabled(String scheme) { + return "apicurio-registry".equals(scheme); + } + + @Override + public String buildUri(String scheme, Map properties, boolean encode) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + Map copy = new HashMap<>(properties); + + uri = buildPathParameter(syntax, uri, "groupId", null, false, copy); + uri = buildPathParameter(syntax, uri, "artifactId", null, false, copy); + uri = buildQueryParameters(uri, copy, encode); + return uri; + } + + @Override + public Set propertyNames() { + return PROPERTY_NAMES; + } + + @Override + public Set secretPropertyNames() { + return SECRET_PROPERTY_NAMES; + } + + @Override + public Set endpointIdentityPropertyNames() { + return ENDPOINT_IDENTITY_PROPERTY_NAMES; + } + + @Override + public Map multiValuePrefixes() { + return MULTI_VALUE_PREFIXES; + } + + @Override + public boolean isLenientProperties() { + return false; + } +} + diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerInvokeOnHeaderFactory.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerInvokeOnHeaderFactory.java new file mode 100644 index 0000000000000..4135109707e99 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerInvokeOnHeaderFactory.java @@ -0,0 +1,46 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.apicurioregistry; + +import javax.annotation.processing.Generated; + +import org.apache.camel.AsyncCallback; +import org.apache.camel.Exchange; +import org.apache.camel.spi.InvokeOnHeaderStrategy; +import org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@SuppressWarnings("unchecked") +@Generated("org.apache.camel.maven.packaging.GenerateInvokeOnHeaderMojo") +public class ApicurioRegistryProducerInvokeOnHeaderFactory implements InvokeOnHeaderStrategy { + + @Override + public Object invoke(Object obj, String key, Exchange exchange, AsyncCallback callback) throws Exception { + org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer target = (org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer) obj; + switch (key) { + case "createartifact": + case "createArtifact": target.createArtifact(exchange.getMessage()); return null; + case "creategroup": + case "createGroup": target.createGroup(exchange.getMessage()); return null; + case "deleteartifact": + case "deleteArtifact": target.deleteArtifact(exchange.getMessage()); return null; + case "getartifactcontent": + case "getArtifactContent": target.getArtifactContent(exchange.getMessage()); return null; + case "getartifactmetadata": + case "getArtifactMetadata": target.getArtifactMetadata(exchange.getMessage()); return null; + case "listversions": + case "listVersions": target.listVersions(exchange.getMessage()); return null; + case "searchartifacts": + case "searchArtifacts": target.searchArtifacts(exchange.getMessage()); return null; + case "testcompatibility": + case "testCompatibility": target.testCompatibility(exchange.getMessage()); return null; + case "updateartifact": + case "updateArtifact": target.updateArtifact(exchange.getMessage()); return null; + case "validate": target.validate(exchange.getMessage()); return null; + default: return null; + } + } + +} + diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json b/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json new file mode 100644 index 0000000000000..82bea993998e5 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json @@ -0,0 +1,102 @@ +{ + "component": { + "kind": "component", + "name": "apicurio-registry", + "title": "Apicurio Registry", + "description": "Manage artifacts, versions, and groups in Apicurio Registry v3.", + "deprecated": false, + "firstVersion": "4.22.0", + "label": "cloud,api", + "javaType": "org.apache.camel.component.apicurioregistry.ApicurioRegistryComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-apicurio-registry", + "version": "4.22.0-SNAPSHOT", + "scheme": "apicurio-registry", + "extendsScheme": "", + "syntax": "apicurio-registry:groupId\/artifactId", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false, + "browsable": false, + "remote": true + }, + "componentProperties": { + "registryUrl": { "index": 0, "kind": "property", "displayName": "Registry Url", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The Apicurio Registry base URL" }, + "bridgeErrorHandler": { "index": 1, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "fetchContent": { "index": 2, "kind": "property", "displayName": "Fetch Content", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to fetch the content for each new version found by the consumer" }, + "artifactType": { "index": 3, "kind": "property", "displayName": "Artifact Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "JSON", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The default artifact type" }, + "cacheTtl": { "index": 4, "kind": "property", "displayName": "Cache Ttl", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 300000, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Schema cache TTL in milliseconds for the validate operation. 0 means no caching." }, + "failOnValidation": { "index": 5, "kind": "property", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, + "ifExists": { "index": 6, "kind": "property", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, + "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "operation": { "index": 8, "kind": "property", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, + "autowiredEnabled": { "index": 9, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "configuration": { "index": 10, "kind": "property", "displayName": "Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The component configuration" }, + "authType": { "index": 11, "kind": "property", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, + "clientId": { "index": 12, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, + "clientSecret": { "index": 13, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, + "password": { "index": 14, "kind": "property", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, + "scope": { "index": 15, "kind": "property", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, + "tokenEndpoint": { "index": 16, "kind": "property", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, + "username": { "index": 17, "kind": "property", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } + }, + "headers": { + "CamelApicurioRegistryOperation": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_OPERATION" }, + "CamelApicurioRegistryGroupId": { "index": 1, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact group ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_GROUP_ID" }, + "CamelApicurioRegistryArtifactId": { "index": 2, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_ARTIFACT_ID" }, + "CamelApicurioRegistryArtifactType": { "index": 3, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact type (e.g. AVRO, PROTOBUF, JSON, OPENAPI)", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_ARTIFACT_TYPE" }, + "CamelApicurioRegistryVersion": { "index": 4, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact version expression", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VERSION" }, + "CamelApicurioRegistryArtifactName": { "index": 5, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact name", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_ARTIFACT_NAME" }, + "CamelApicurioRegistryArtifactDescription": { "index": 6, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact description", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_ARTIFACT_DESCRIPTION" }, + "CamelApicurioRegistryIfExists": { "index": 7, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Behavior when artifact already exists (FAIL, CREATE_VERSION, FIND_OR_CREATE_VERSION)", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_IF_EXISTS" }, + "CamelApicurioRegistryContentType": { "index": 8, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content type of the artifact", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_CONTENT_TYPE" }, + "CamelApicurioRegistryDryRun": { "index": 9, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether the operation is a dry run", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_DRY_RUN" }, + "CamelApicurioRegistryGlobalId": { "index": 10, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version global ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_GLOBAL_ID" }, + "CamelApicurioRegistryContentId": { "index": 11, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_CONTENT_ID" }, + "CamelApicurioRegistryVersionState": { "index": 12, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version state", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VERSION_STATE" }, + "CamelApicurioRegistryValidationResult": { "index": 13, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether validation passed", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_RESULT" }, + "CamelApicurioRegistryValidationErrors": { "index": 14, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Validation error details", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_ERRORS" } + }, + "properties": { + "groupId": { "index": 0, "kind": "path", "displayName": "Group Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The artifact group ID" }, + "artifactId": { "index": 1, "kind": "path", "displayName": "Artifact Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The artifact ID" }, + "registryUrl": { "index": 2, "kind": "parameter", "displayName": "Registry Url", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The Apicurio Registry base URL" }, + "fetchContent": { "index": 3, "kind": "parameter", "displayName": "Fetch Content", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to fetch the content for each new version found by the consumer" }, + "sendEmptyMessageWhenIdle": { "index": 4, "kind": "parameter", "displayName": "Send Empty Message When Idle", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If the polling consumer did not poll any files, you can enable this option to send an empty message (no body) instead." }, + "bridgeErrorHandler": { "index": 5, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exceptionHandler": { "index": 6, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, + "exchangePattern": { "index": 7, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "pollStrategy": { "index": 8, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, + "artifactType": { "index": 9, "kind": "parameter", "displayName": "Artifact Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "JSON", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The default artifact type" }, + "cacheTtl": { "index": 10, "kind": "parameter", "displayName": "Cache Ttl", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 300000, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Schema cache TTL in milliseconds for the validate operation. 0 means no caching." }, + "failOnValidation": { "index": 11, "kind": "parameter", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, + "ifExists": { "index": 12, "kind": "parameter", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, + "operation": { "index": 13, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, + "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "registryClient": { "index": 15, "kind": "parameter", "displayName": "Registry Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.apicurio.registry.rest.client.RegistryClient", "deprecated": false, "autowired": false, "secret": false, "description": "To use a pre-configured RegistryClient instance" }, + "backoffErrorThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 17, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 18, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 19, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 20, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 21, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 22, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 23, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 24, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 25, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 26, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 27, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 28, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 29, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "authType": { "index": 30, "kind": "parameter", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, + "clientId": { "index": 31, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, + "clientSecret": { "index": 32, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, + "password": { "index": 33, "kind": "parameter", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, + "scope": { "index": 34, "kind": "parameter", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, + "tokenEndpoint": { "index": 35, "kind": "parameter", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, + "username": { "index": 36, "kind": "parameter", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } + } +} diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component.properties new file mode 100644 index 0000000000000..d66643d9caeb5 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +components=apicurio-registry +groupId=org.apache.camel +artifactId=camel-apicurio-registry +version=4.22.0-SNAPSHOT +projectName=Camel :: Apicurio Registry +projectDescription=Camel Apicurio Registry component diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component/apicurio-registry b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component/apicurio-registry new file mode 100644 index 0000000000000..50039a4ef48d3 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/component/apicurio-registry @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.apicurioregistry.ApicurioRegistryComponent diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-component b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-component new file mode 100644 index 0000000000000..a094536fd4c8a --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-component @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.apicurioregistry.ApicurioRegistryComponentConfigurer diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-endpoint b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-endpoint new file mode 100644 index 0000000000000..b6875b4afe891 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/configurer/apicurio-registry-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.apicurioregistry.ApicurioRegistryEndpointConfigurer diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/invoke-on-header/org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/invoke-on-header/org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer new file mode 100644 index 0000000000000..7ae68a23a7bc4 --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/invoke-on-header/org.apache.camel.component.apicurioregistry.ApicurioRegistryProducer @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.apicurioregistry.ApicurioRegistryProducerInvokeOnHeaderFactory diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/urifactory/apicurio-registry-endpoint b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/urifactory/apicurio-registry-endpoint new file mode 100644 index 0000000000000..a92bb3a88709f --- /dev/null +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/services/org/apache/camel/urifactory/apicurio-registry-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.apicurioregistry.ApicurioRegistryEndpointUriFactory diff --git a/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc b/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc new file mode 100644 index 0000000000000..950f4c6e8c3c9 --- /dev/null +++ b/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc @@ -0,0 +1,198 @@ += Apicurio Registry Component +:doctitle: Apicurio Registry +:shortname: apicurio-registry +:artifactid: camel-apicurio-registry +:description: Manage artifacts, versions, and groups in Apicurio Registry v3. +:since: 4.22 +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported + +*Since Camel {since}* + +*{component-header}* + +The Apicurio Registry component provides integration with https://www.apicur.io/registry/[Apicurio Registry] v3 +using the https://github.com/Apicurio/apicurio-registry[Apicurio Registry Java SDK]. + +It supports CRUD operations on artifacts, groups, and versions, as well as schema validation +and polling for new artifact versions. + +Maven users will need to add the following dependency to their `pom.xml` +for this component: + +[source,xml] +---- + + org.apache.camel + camel-apicurio-registry + x.x.x + + +---- + +== URI format + +---- +apicurio-registry:groupId/artifactId[?options] +---- + +Where `groupId` and `artifactId` identify the registry artifact. Both are optional for +operations that do not require them (e.g., `searchArtifacts`, `createGroup`). + +// component options: START +include::partial$component-configure-options.adoc[] +include::partial$component-endpoint-options.adoc[] +include::partial$component-endpoint-headers.adoc[] +// component options: END + +== Producer Operations + +The producer supports the following operations, set via the `operation` endpoint option or +the `CamelApicurioRegistryOperation` header: + +[cols="1,3"] +|=== +| Operation | Description + +| `createArtifact` | Create a new artifact. Body contains the artifact content. +| `updateArtifact` | Create a new version of an existing artifact. Body contains the new content. +| `deleteArtifact` | Delete an artifact. +| `getArtifactContent` | Retrieve the content of an artifact version. +| `getArtifactMetadata` | Retrieve artifact metadata. +| `searchArtifacts` | Search for artifacts using filter headers. +| `listVersions` | List all versions of an artifact. +| `createGroup` | Create a new group. +| `testCompatibility` | Test schema compatibility (dry run). Returns `true`/`false` in the body. +| `validate` | Validate the message body against the artifact's rules (dry run). Throws `ApicurioRegistryValidationException` on failure when `failOnValidation=true`. +|=== + +== Consumer + +The consumer polls the registry for new versions of the specified artifact. It tracks the last +seen `globalId` and only delivers new versions. Set the `delay` option to control the polling +interval (default: 500ms). + +When `fetchContent=true`, the consumer fetches the version content and sets it as the exchange body. +Otherwise, the version metadata object is set as the body. + +== Examples + +=== Create an artifact + +[tabs] +==== +Java:: ++ +[source,java] +---- +from("direct:create") + .setBody(constant("{\"type\":\"record\",\"name\":\"Test\",\"fields\":[]}")) + .to("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=createArtifact&artifactType=AVRO"); +---- + +XML:: ++ +[source,xml] +---- + + + {"type":"record","name":"Test","fields":[]} + + +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: direct:create + steps: + - setBody: + constant: '{"type":"record","name":"Test","fields":[]}' + - to: + uri: apicurio-registry:myGroup/myArtifact + parameters: + registryUrl: http://localhost:8080/apis/registry/v3 + operation: createArtifact + artifactType: AVRO +---- +==== + +=== Poll for new versions + +[tabs] +==== +Java:: ++ +[source,java] +---- +from("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=5000") + .log("New version detected: ${header.CamelApicurioRegistryVersion}") + .to("log:newVersions"); +---- + +XML:: ++ +[source,xml] +---- + + + + + +---- + +YAML:: ++ +[source,yaml] +---- +- route: + from: + uri: apicurio-registry:myGroup/myArtifact + parameters: + registryUrl: http://localhost:8080/apis/registry/v3 + delay: 5000 + steps: + - log: + message: "New version detected: ${header.CamelApicurioRegistryVersion}" + - to: + uri: log:newVersions +---- +==== + +=== Validate message against a schema + +[source,java] +---- +from("platform-http:/orders") + .doTry() + .to("apicurio-registry:my-group/order-schema?operation=validate®istryUrl=http://localhost:8080/apis/registry/v3") + .to("bean:orderService") + .doCatch(ApicurioRegistryValidationException.class) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(400)) + .setBody(simple("${exception.validationErrors}")) + .end(); +---- + +== Authentication + +The component supports three authentication modes via the `authType` option: + +* `none` (default): No authentication. +* `basic`: Basic authentication using `username` and `password`. +* `oidc`: OAuth2/OIDC using `tokenEndpoint`, `clientId`, `clientSecret`, and optionally `scope`. + +Example with OIDC: + +[source,java] +---- +from("direct:secured") + .to("apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3" + + "&operation=getArtifactContent" + + "&authType=oidc" + + "&tokenEndpoint=http://keycloak:8080/realms/registry/protocol/openid-connect/token" + + "&clientId=registry-client&clientSecret=secret"); +---- diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponent.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponent.java new file mode 100644 index 0000000000000..7d84b31de215e --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponent.java @@ -0,0 +1,66 @@ +/* + * 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.camel.component.apicurioregistry; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.annotations.Component; +import org.apache.camel.support.DefaultComponent; + +@Component("apicurio-registry") +public class ApicurioRegistryComponent extends DefaultComponent { + + @Metadata(label = "advanced", description = "The component configuration") + private ApicurioRegistryConfiguration configuration = new ApicurioRegistryConfiguration(); + + public ApicurioRegistryComponent() { + } + + public ApicurioRegistryComponent(CamelContext context) { + super(context); + } + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception { + ApicurioRegistryConfiguration config = this.configuration.copy(); + + String groupId = null; + String artifactId = null; + if (remaining != null && !remaining.isEmpty()) { + String[] parts = remaining.split("/", 2); + groupId = parts[0]; + if (parts.length > 1 && !parts[1].isEmpty()) { + artifactId = parts[1]; + } + } + + ApicurioRegistryEndpoint endpoint = new ApicurioRegistryEndpoint(uri, this, config, groupId, artifactId); + setProperties(endpoint, parameters); + return endpoint; + } + + public ApicurioRegistryConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration(ApicurioRegistryConfiguration configuration) { + this.configuration = configuration; + } +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java new file mode 100644 index 0000000000000..99f3091e81a80 --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java @@ -0,0 +1,201 @@ +/* + * 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.camel.component.apicurioregistry; + +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; + +@UriParams +public class ApicurioRegistryConfiguration implements Cloneable { + + @UriParam(label = "common", description = "The Apicurio Registry base URL") + @Metadata(required = true) + private String registryUrl; + + @UriParam(label = "producer", + enums = "createArtifact,updateArtifact,deleteArtifact,getArtifactContent,getArtifactMetadata,searchArtifacts,listVersions,createGroup,testCompatibility,validate", + description = "The operation to perform") + private String operation; + + @UriParam(label = "producer", description = "The default artifact type", defaultValue = "JSON") + private String artifactType = "JSON"; + + @UriParam(label = "security", enums = "none,basic,oidc", defaultValue = "none", + description = "The authentication type to use") + private String authType = "none"; + + @UriParam(label = "security", security = "secret", description = "Username for basic authentication") + private String username; + + @UriParam(label = "security", security = "secret", description = "Password for basic authentication") + private String password; + + @UriParam(label = "security", description = "OAuth2 token endpoint URL") + private String tokenEndpoint; + + @UriParam(label = "security", security = "secret", description = "OAuth2 client ID") + private String clientId; + + @UriParam(label = "security", security = "secret", description = "OAuth2 client secret") + private String clientSecret; + + @UriParam(label = "security", description = "OAuth2 scope") + private String scope; + + @UriParam(label = "producer", + description = "Behavior when artifact already exists", + enums = "FAIL,CREATE_VERSION,FIND_OR_CREATE_VERSION", + defaultValue = "FAIL") + private String ifExists = "FAIL"; + + @UriParam(label = "consumer", + description = "Whether to fetch the content for each new version found by the consumer", + defaultValue = "false") + private boolean fetchContent; + + @UriParam(label = "producer", + description = "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead.", + defaultValue = "true") + private boolean failOnValidation = true; + + @UriParam(label = "producer", + description = "Schema cache TTL in milliseconds for the validate operation. 0 means no caching.", + defaultValue = "300000") + private long cacheTtl = 300000; + + public String getRegistryUrl() { + return registryUrl; + } + + public void setRegistryUrl(String registryUrl) { + this.registryUrl = registryUrl; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public String getArtifactType() { + return artifactType; + } + + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + public String getAuthType() { + return authType; + } + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getTokenEndpoint() { + return tokenEndpoint; + } + + public void setTokenEndpoint(String tokenEndpoint) { + this.tokenEndpoint = tokenEndpoint; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getIfExists() { + return ifExists; + } + + public void setIfExists(String ifExists) { + this.ifExists = ifExists; + } + + public boolean isFetchContent() { + return fetchContent; + } + + public void setFetchContent(boolean fetchContent) { + this.fetchContent = fetchContent; + } + + public boolean isFailOnValidation() { + return failOnValidation; + } + + public void setFailOnValidation(boolean failOnValidation) { + this.failOnValidation = failOnValidation; + } + + public long getCacheTtl() { + return cacheTtl; + } + + public void setCacheTtl(long cacheTtl) { + this.cacheTtl = cacheTtl; + } + + public ApicurioRegistryConfiguration copy() { + try { + return (ApicurioRegistryConfiguration) super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeCamelException(e); + } + } +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java new file mode 100644 index 0000000000000..f190390be696f --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java @@ -0,0 +1,79 @@ +/* + * 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.camel.component.apicurioregistry; + +import org.apache.camel.spi.Metadata; + +public interface ApicurioRegistryConstants { + + @Metadata(description = "The operation to perform", javaType = "String") + String HEADER_OPERATION = "CamelApicurioRegistryOperation"; + + @Metadata(description = "The artifact group ID", javaType = "String") + String HEADER_GROUP_ID = "CamelApicurioRegistryGroupId"; + + @Metadata(description = "The artifact ID", javaType = "String") + String HEADER_ARTIFACT_ID = "CamelApicurioRegistryArtifactId"; + + @Metadata(description = "The artifact type (e.g. AVRO, PROTOBUF, JSON, OPENAPI)", javaType = "String") + String HEADER_ARTIFACT_TYPE = "CamelApicurioRegistryArtifactType"; + + @Metadata(description = "The artifact version expression", javaType = "String") + String HEADER_VERSION = "CamelApicurioRegistryVersion"; + + @Metadata(description = "The artifact name", javaType = "String") + String HEADER_ARTIFACT_NAME = "CamelApicurioRegistryArtifactName"; + + @Metadata(description = "The artifact description", javaType = "String") + String HEADER_ARTIFACT_DESCRIPTION = "CamelApicurioRegistryArtifactDescription"; + + @Metadata(description = "Behavior when artifact already exists (FAIL, CREATE_VERSION, FIND_OR_CREATE_VERSION)", + javaType = "String") + String HEADER_IF_EXISTS = "CamelApicurioRegistryIfExists"; + + @Metadata(description = "The content type of the artifact", javaType = "String") + String HEADER_CONTENT_TYPE = "CamelApicurioRegistryContentType"; + + @Metadata(description = "Whether the operation is a dry run", javaType = "Boolean") + String HEADER_DRY_RUN = "CamelApicurioRegistryDryRun"; + + @Metadata(label = "consumer", description = "The version global ID", javaType = "Long") + String HEADER_GLOBAL_ID = "CamelApicurioRegistryGlobalId"; + + @Metadata(label = "consumer", description = "The content ID", javaType = "Long") + String HEADER_CONTENT_ID = "CamelApicurioRegistryContentId"; + + @Metadata(label = "consumer", description = "The version state", javaType = "String") + String HEADER_VERSION_STATE = "CamelApicurioRegistryVersionState"; + + @Metadata(description = "Whether validation passed", javaType = "Boolean") + String HEADER_VALIDATION_RESULT = "CamelApicurioRegistryValidationResult"; + + @Metadata(description = "Validation error details", javaType = "String") + String HEADER_VALIDATION_ERRORS = "CamelApicurioRegistryValidationErrors"; + + String OPERATION_CREATE_ARTIFACT = "createArtifact"; + String OPERATION_UPDATE_ARTIFACT = "updateArtifact"; + String OPERATION_DELETE_ARTIFACT = "deleteArtifact"; + String OPERATION_GET_ARTIFACT_CONTENT = "getArtifactContent"; + String OPERATION_GET_ARTIFACT_METADATA = "getArtifactMetadata"; + String OPERATION_SEARCH_ARTIFACTS = "searchArtifacts"; + String OPERATION_LIST_VERSIONS = "listVersions"; + String OPERATION_CREATE_GROUP = "createGroup"; + String OPERATION_TEST_COMPATIBILITY = "testCompatibility"; + String OPERATION_VALIDATE = "validate"; +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java new file mode 100644 index 0000000000000..07842bfd796ff --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java @@ -0,0 +1,99 @@ +/* + * 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.camel.component.apicurioregistry; + +import java.io.InputStream; +import java.util.List; + +import io.apicurio.registry.rest.client.RegistryClient; +import io.apicurio.registry.rest.client.models.SearchedVersion; +import io.apicurio.registry.rest.client.models.VersionSearchResults; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Processor; +import org.apache.camel.support.ScheduledPollConsumer; + +public class ApicurioRegistryConsumer extends ScheduledPollConsumer { + + private final ApicurioRegistryEndpoint endpoint; + private final ApicurioRegistryConfiguration configuration; + private volatile Long lastSeenGlobalId; + + public ApicurioRegistryConsumer(ApicurioRegistryEndpoint endpoint, Processor processor, + ApicurioRegistryConfiguration configuration) { + super(endpoint, processor); + this.endpoint = endpoint; + this.configuration = configuration; + } + + @Override + protected int poll() throws Exception { + String groupId = endpoint.getGroupId(); + String artifactId = endpoint.getArtifactId(); + + if (groupId == null || artifactId == null) { + throw new IllegalArgumentException( + "Both groupId and artifactId are required for the consumer"); + } + + RegistryClient client = endpoint.getRegistryClient(); + VersionSearchResults results = client.groups().byGroupId(groupId) + .artifacts().byArtifactId(artifactId).versions().get(); + + if (results == null || results.getVersions() == null) { + return 0; + } + + List versions = results.getVersions(); + int count = 0; + for (SearchedVersion version : versions) { + Long globalId = version.getGlobalId(); + if (lastSeenGlobalId == null || globalId > lastSeenGlobalId) { + Exchange exchange = createExchange(true); + Message message = exchange.getIn(); + + message.setHeader(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + message.setHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + message.setHeader(ApicurioRegistryConstants.HEADER_VERSION, version.getVersion()); + message.setHeader(ApicurioRegistryConstants.HEADER_GLOBAL_ID, globalId); + message.setHeader(ApicurioRegistryConstants.HEADER_CONTENT_ID, version.getContentId()); + message.setHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, version.getArtifactType()); + if (version.getState() != null) { + message.setHeader(ApicurioRegistryConstants.HEADER_VERSION_STATE, + version.getState().getValue()); + } + + if (configuration.isFetchContent()) { + InputStream content = client.groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions() + .byVersionExpression(version.getVersion()).content().get(); + message.setBody(content); + } else { + message.setBody(version); + } + + getProcessor().process(exchange); + + if (lastSeenGlobalId == null || globalId > lastSeenGlobalId) { + lastSeenGlobalId = globalId; + } + count++; + } + } + return count; + } +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpoint.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpoint.java new file mode 100644 index 0000000000000..5d6b9dc464a14 --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpoint.java @@ -0,0 +1,132 @@ +/* + * 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.camel.component.apicurioregistry; + +import io.apicurio.registry.client.RegistryClientFactory; +import io.apicurio.registry.client.common.RegistryClientOptions; +import io.apicurio.registry.rest.client.RegistryClient; +import org.apache.camel.Category; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.spi.EndpointServiceLocation; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.ScheduledPollEndpoint; + +/** + * Manage artifacts, versions, and groups in Apicurio Registry v3. + */ +@UriEndpoint(firstVersion = "4.22.0", scheme = "apicurio-registry", title = "Apicurio Registry", + syntax = "apicurio-registry:groupId/artifactId", + category = { Category.CLOUD, Category.API }, headersClass = ApicurioRegistryConstants.class) +public class ApicurioRegistryEndpoint extends ScheduledPollEndpoint implements EndpointServiceLocation { + + @UriPath(description = "The artifact group ID") + private String groupId; + + @UriPath(description = "The artifact ID") + private String artifactId; + + @UriParam + private ApicurioRegistryConfiguration configuration; + + @UriParam(label = "advanced", description = "To use a pre-configured RegistryClient instance") + private RegistryClient registryClient; + + ApicurioRegistryEndpoint(String uri, ApicurioRegistryComponent component, + ApicurioRegistryConfiguration configuration, + String groupId, String artifactId) { + super(uri, component); + this.configuration = configuration; + this.groupId = groupId; + this.artifactId = artifactId; + } + + @Override + public Producer createProducer() throws Exception { + return new ApicurioRegistryProducer(this, configuration); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + ApicurioRegistryConsumer consumer = new ApicurioRegistryConsumer(this, processor, configuration); + configureConsumer(consumer); + return consumer; + } + + @Override + protected void doStart() throws Exception { + super.doStart(); + if (registryClient == null) { + registryClient = createRegistryClient(); + } + } + + @Override + protected void doStop() throws Exception { + super.doStop(); + registryClient = null; + } + + private RegistryClient createRegistryClient() { + RegistryClientOptions options = RegistryClientOptions.create(configuration.getRegistryUrl()); + String authType = configuration.getAuthType(); + if ("basic".equalsIgnoreCase(authType)) { + options.basicAuth(configuration.getUsername(), configuration.getPassword()); + } else if ("oidc".equalsIgnoreCase(authType)) { + options.oauth2(configuration.getTokenEndpoint(), configuration.getClientId(), + configuration.getClientSecret(), configuration.getScope()); + } + return RegistryClientFactory.create(options); + } + + public RegistryClient getRegistryClient() { + return registryClient; + } + + public void setRegistryClient(RegistryClient registryClient) { + this.registryClient = registryClient; + } + + public String getGroupId() { + return groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public ApicurioRegistryConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration(ApicurioRegistryConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public String getServiceUrl() { + return configuration.getRegistryUrl(); + } + + @Override + public String getServiceProtocol() { + return "http"; + } +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java new file mode 100644 index 0000000000000..13b5face56ed1 --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java @@ -0,0 +1,247 @@ +/* + * 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.camel.component.apicurioregistry; + +import java.io.InputStream; + +import io.apicurio.registry.rest.client.RegistryClient; +import io.apicurio.registry.rest.client.models.ArtifactMetaData; +import io.apicurio.registry.rest.client.models.CreateArtifact; +import io.apicurio.registry.rest.client.models.CreateArtifactResponse; +import io.apicurio.registry.rest.client.models.CreateGroup; +import io.apicurio.registry.rest.client.models.CreateVersion; +import io.apicurio.registry.rest.client.models.GroupMetaData; +import io.apicurio.registry.rest.client.models.IfArtifactExists; +import io.apicurio.registry.rest.client.models.VersionContent; +import io.apicurio.registry.rest.client.models.VersionMetaData; +import io.apicurio.registry.rest.client.models.VersionSearchResults; +import org.apache.camel.Message; +import org.apache.camel.spi.InvokeOnHeader; +import org.apache.camel.support.HeaderSelectorProducer; + +public class ApicurioRegistryProducer extends HeaderSelectorProducer { + + private final ApicurioRegistryEndpoint endpoint; + private final ApicurioRegistryConfiguration configuration; + + public ApicurioRegistryProducer(ApicurioRegistryEndpoint endpoint, + ApicurioRegistryConfiguration configuration) { + super(endpoint, ApicurioRegistryConstants.HEADER_OPERATION, configuration::getOperation); + this.endpoint = endpoint; + this.configuration = configuration; + } + + private RegistryClient getClient() { + return endpoint.getRegistryClient(); + } + + private String resolveGroupId(Message message) { + String gid = message.getHeader(ApicurioRegistryConstants.HEADER_GROUP_ID, String.class); + return gid != null ? gid : endpoint.getGroupId(); + } + + private String resolveArtifactId(Message message) { + String aid = message.getHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, String.class); + return aid != null ? aid : endpoint.getArtifactId(); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_CREATE_ARTIFACT) + public void createArtifact(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + String artifactType = message.getHeader( + ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, configuration.getArtifactType(), String.class); + String name = message.getHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_NAME, String.class); + String description = message.getHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_DESCRIPTION, String.class); + String content = message.getBody(String.class); + String contentType = message.getHeader( + ApicurioRegistryConstants.HEADER_CONTENT_TYPE, "application/json", String.class); + String ifExistsVal = message.getHeader( + ApicurioRegistryConstants.HEADER_IF_EXISTS, configuration.getIfExists(), String.class); + + CreateArtifact createArtifact = new CreateArtifact(); + createArtifact.setArtifactId(artifactId); + createArtifact.setArtifactType(artifactType); + createArtifact.setName(name); + createArtifact.setDescription(description); + + if (content != null) { + CreateVersion firstVersion = new CreateVersion(); + VersionContent vc = new VersionContent(); + vc.setContent(content); + vc.setContentType(contentType); + firstVersion.setContent(vc); + createArtifact.setFirstVersion(firstVersion); + } + + CreateArtifactResponse result = getClient().groups().byGroupId(groupId).artifacts() + .post(createArtifact, config -> { + if (ifExistsVal != null) { + config.queryParameters.ifExists = IfArtifactExists.forValue(ifExistsVal); + } + }); + message.setBody(result); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_UPDATE_ARTIFACT) + public void updateArtifact(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + String content = message.getBody(String.class); + String version = message.getHeader(ApicurioRegistryConstants.HEADER_VERSION, String.class); + String contentType = message.getHeader( + ApicurioRegistryConstants.HEADER_CONTENT_TYPE, "application/json", String.class); + + CreateVersion createVersion = new CreateVersion(); + createVersion.setVersion(version); + VersionContent vc = new VersionContent(); + vc.setContent(content); + vc.setContentType(contentType); + createVersion.setContent(vc); + + VersionMetaData result = getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions().post(createVersion); + message.setBody(result); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_DELETE_ARTIFACT) + public void deleteArtifact(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + getClient().groups().byGroupId(groupId).artifacts().byArtifactId(artifactId).delete(); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_CONTENT) + public void getArtifactContent(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + String version = message.getHeader( + ApicurioRegistryConstants.HEADER_VERSION, "branch=latest", String.class); + + InputStream content = getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions().byVersionExpression(version).content().get(); + message.setBody(content); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_METADATA) + public void getArtifactMetadata(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + + ArtifactMetaData metadata = getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).get(); + message.setBody(metadata); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_SEARCH_ARTIFACTS) + public void searchArtifacts(Message message) { + var results = getClient().search().artifacts().get(config -> { + String name = message.getHeader(ApicurioRegistryConstants.HEADER_ARTIFACT_NAME, String.class); + String groupId = resolveGroupId(message); + String description = message.getHeader( + ApicurioRegistryConstants.HEADER_ARTIFACT_DESCRIPTION, String.class); + if (name != null) { + config.queryParameters.name = name; + } + if (groupId != null) { + config.queryParameters.groupId = groupId; + } + if (description != null) { + config.queryParameters.description = description; + } + }); + message.setBody(results); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_LIST_VERSIONS) + public void listVersions(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + + VersionSearchResults results = getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions().get(); + message.setBody(results); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_CREATE_GROUP) + public void createGroup(Message message) { + String groupId = resolveGroupId(message); + String description = message.getHeader( + ApicurioRegistryConstants.HEADER_ARTIFACT_DESCRIPTION, String.class); + + CreateGroup createGroup = new CreateGroup(); + createGroup.setGroupId(groupId); + createGroup.setDescription(description); + + GroupMetaData result = getClient().groups().post(createGroup); + message.setBody(result); + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_TEST_COMPATIBILITY) + public void testCompatibility(Message message) { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + String content = message.getBody(String.class); + String contentType = message.getHeader( + ApicurioRegistryConstants.HEADER_CONTENT_TYPE, "application/json", String.class); + + CreateVersion createVersion = new CreateVersion(); + VersionContent vc = new VersionContent(); + vc.setContent(content); + vc.setContentType(contentType); + createVersion.setContent(vc); + + try { + getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions() + .post(createVersion, config -> config.queryParameters.dryRun = true); + message.setBody(true); + } catch (Exception e) { + message.setBody(false); + message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS, e.getMessage()); + } + } + + @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_VALIDATE) + public void validate(Message message) throws Exception { + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + String content = message.getBody(String.class); + String contentType = message.getHeader( + ApicurioRegistryConstants.HEADER_CONTENT_TYPE, "application/json", String.class); + + CreateVersion createVersion = new CreateVersion(); + VersionContent vc = new VersionContent(); + vc.setContent(content); + vc.setContentType(contentType); + createVersion.setContent(vc); + + try { + getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions() + .post(createVersion, config -> config.queryParameters.dryRun = true); + message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, true); + } catch (Exception e) { + message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, false); + message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS, e.getMessage()); + if (configuration.isFailOnValidation()) { + throw new ApicurioRegistryValidationException( + "Validation failed for artifact " + groupId + "/" + artifactId, e.getMessage()); + } + } + } +} diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryValidationException.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryValidationException.java new file mode 100644 index 0000000000000..19855437cb093 --- /dev/null +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryValidationException.java @@ -0,0 +1,33 @@ +/* + * 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.camel.component.apicurioregistry; + +import org.apache.camel.CamelException; + +public class ApicurioRegistryValidationException extends CamelException { + + private final String validationErrors; + + public ApicurioRegistryValidationException(String message, String validationErrors) { + super(message); + this.validationErrors = validationErrors; + } + + public String getValidationErrors() { + return validationErrors; + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentTest.java new file mode 100644 index 0000000000000..70424783ce1b2 --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentTest.java @@ -0,0 +1,89 @@ +/* + * 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.camel.component.apicurioregistry; + +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +class ApicurioRegistryComponentTest extends CamelTestSupport { + + @Test + void testEndpointCreatedWithGroupAndArtifact() throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:myGroup/myArtifact?registryUrl=http://localhost:8080/apis/registry/v3"); + assertNotNull(endpoint); + assertEquals("myGroup", endpoint.getGroupId()); + assertEquals("myArtifact", endpoint.getArtifactId()); + assertEquals("http://localhost:8080/apis/registry/v3", endpoint.getConfiguration().getRegistryUrl()); + } + + @Test + void testEndpointCreatedWithGroupOnly() throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:myGroup?registryUrl=http://localhost:8080/apis/registry/v3"); + assertNotNull(endpoint); + assertEquals("myGroup", endpoint.getGroupId()); + assertNull(endpoint.getArtifactId()); + } + + @Test + void testEndpointWithAuthOptions() throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:g/a?registryUrl=http://localhost:8080/apis/registry/v3" + + "&authType=basic&username=user&password=pass"); + assertNotNull(endpoint); + assertEquals("basic", endpoint.getConfiguration().getAuthType()); + assertEquals("user", endpoint.getConfiguration().getUsername()); + assertEquals("pass", endpoint.getConfiguration().getPassword()); + } + + @Test + void testEndpointWithOperationOption() throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:g/a?registryUrl=http://localhost:8080/apis/registry/v3" + + "&operation=createArtifact"); + assertNotNull(endpoint); + assertEquals("createArtifact", endpoint.getConfiguration().getOperation()); + } + + @Test + void testConfigurationCopy() { + ApicurioRegistryConfiguration config = new ApicurioRegistryConfiguration(); + config.setRegistryUrl("http://localhost:8080"); + config.setOperation("createArtifact"); + config.setAuthType("basic"); + config.setUsername("user"); + + ApicurioRegistryConfiguration copy = config.copy(); + assertEquals(config.getRegistryUrl(), copy.getRegistryUrl()); + assertEquals(config.getOperation(), copy.getOperation()); + assertEquals(config.getAuthType(), copy.getAuthType()); + assertEquals(config.getUsername(), copy.getUsername()); + } + + @Test + void testEndpointServiceLocation() throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:g/a?registryUrl=http://localhost:8080/apis/registry/v3"); + assertEquals("http://localhost:8080/apis/registry/v3", endpoint.getServiceUrl()); + assertEquals("http", endpoint.getServiceProtocol()); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java new file mode 100644 index 0000000000000..0976f3abbea35 --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java @@ -0,0 +1,112 @@ +/* + * 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.camel.component.apicurioregistry; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import io.apicurio.registry.rest.client.RegistryClient; +import io.apicurio.registry.rest.client.models.SearchedVersion; +import io.apicurio.registry.rest.client.models.VersionSearchResults; +import org.apache.camel.BindToRegistry; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ApicurioRegistryConsumerTest extends CamelTestSupport { + + private final RegistryClient mockClient = mock(RegistryClient.class, org.mockito.Mockito.RETURNS_DEEP_STUBS); + + @BindToRegistry("apicurio-registry") + public ApicurioRegistryComponent getComponent() { + ApicurioRegistryComponent component = new ApicurioRegistryComponent(context); + component.getConfiguration().setRegistryUrl("http://localhost:8080/apis/registry/v3"); + return component; + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=500") + .to("mock:result"); + } + }; + } + + private void injectMockClient() { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( + "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=500"); + endpoint.setRegistryClient(mockClient); + } + + @Test + void testPollNewVersions() throws Exception { + injectMockClient(); + + SearchedVersion v1 = new SearchedVersion(); + v1.setGlobalId(1L); + v1.setVersion("1.0"); + v1.setContentId(100L); + v1.setArtifactType("JSON"); + + SearchedVersion v2 = new SearchedVersion(); + v2.setGlobalId(2L); + v2.setVersion("2.0"); + v2.setContentId(101L); + v2.setArtifactType("JSON"); + + VersionSearchResults results = new VersionSearchResults(); + results.setVersions(List.of(v1, v2)); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().get()) + .thenReturn(results); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(2); + MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); + } + + @Test + void testPollNoNewVersionsAfterInitial() throws Exception { + injectMockClient(); + + SearchedVersion v1 = new SearchedVersion(); + v1.setGlobalId(1L); + v1.setVersion("1.0"); + v1.setContentId(100L); + v1.setArtifactType("JSON"); + + VersionSearchResults results = new VersionSearchResults(); + results.setVersions(List.of(v1)); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().get()) + .thenReturn(results); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java new file mode 100644 index 0000000000000..4c76854d4323b --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java @@ -0,0 +1,209 @@ +/* + * 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.camel.component.apicurioregistry; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import io.apicurio.registry.rest.client.RegistryClient; +import io.apicurio.registry.rest.client.models.ArtifactMetaData; +import io.apicurio.registry.rest.client.models.CreateArtifact; +import io.apicurio.registry.rest.client.models.CreateArtifactResponse; +import io.apicurio.registry.rest.client.models.CreateGroup; +import io.apicurio.registry.rest.client.models.CreateVersion; +import io.apicurio.registry.rest.client.models.GroupMetaData; +import io.apicurio.registry.rest.client.models.VersionMetaData; +import io.apicurio.registry.rest.client.models.VersionSearchResults; +import org.apache.camel.BindToRegistry; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class ApicurioRegistryProducerTest extends CamelTestSupport { + + private final RegistryClient mockClient = mock(RegistryClient.class, org.mockito.Mockito.RETURNS_DEEP_STUBS); + + @BindToRegistry("apicurio-registry") + public ApicurioRegistryComponent getComponent() { + ApicurioRegistryComponent component = new ApicurioRegistryComponent(context); + component.getConfiguration().setRegistryUrl("http://localhost:8080/apis/registry/v3"); + return component; + } + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:createArtifact") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=createArtifact"); + + from("direct:deleteArtifact") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=deleteArtifact"); + + from("direct:getArtifactMetadata") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=getArtifactMetadata"); + + from("direct:getArtifactContent") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=getArtifactContent"); + + from("direct:listVersions") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=listVersions"); + + from("direct:createGroup") + .to("apicurio-registry:newGroup?registryUrl=http://localhost:8080/apis/registry/v3&operation=createGroup"); + + from("direct:updateArtifact") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=updateArtifact"); + + from("direct:searchArtifacts") + .to("apicurio-registry:testGroup?registryUrl=http://localhost:8080/apis/registry/v3&operation=searchArtifacts"); + + from("direct:operationFromHeader") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3"); + } + }; + } + + private void injectMockClient(String endpointUri) throws Exception { + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint(endpointUri); + endpoint.setRegistryClient(mockClient); + } + + @Test + void testCreateArtifact() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=createArtifact"; + injectMockClient(endpointUri); + + CreateArtifactResponse mockResponse = new CreateArtifactResponse(); + when(mockClient.groups().byGroupId(anyString()).artifacts().post(any(CreateArtifact.class), any())) + .thenReturn(mockResponse); + + Object result = template.requestBody("direct:createArtifact", "{\"test\":true}"); + assertNotNull(result); + verify(mockClient.groups().byGroupId("testGroup").artifacts()).post(any(CreateArtifact.class), any()); + } + + @Test + void testDeleteArtifact() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=deleteArtifact"; + injectMockClient(endpointUri); + + template.sendBody("direct:deleteArtifact", null); + verify(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact")).delete(); + } + + @Test + void testGetArtifactMetadata() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=getArtifactMetadata"; + injectMockClient(endpointUri); + + ArtifactMetaData mockMetadata = new ArtifactMetaData(); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact").get()) + .thenReturn(mockMetadata); + + Object result = template.requestBody("direct:getArtifactMetadata", (Object) null); + assertEquals(mockMetadata, result); + } + + @Test + void testGetArtifactContent() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=getArtifactContent"; + injectMockClient(endpointUri); + + ByteArrayInputStream mockContent = new ByteArrayInputStream("{\"test\":true}".getBytes(StandardCharsets.UTF_8)); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().byVersionExpression("branch=latest").content().get()) + .thenReturn(mockContent); + + Object result = template.requestBody("direct:getArtifactContent", (Object) null); + assertNotNull(result); + } + + @Test + void testListVersions() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=listVersions"; + injectMockClient(endpointUri); + + VersionSearchResults mockResults = new VersionSearchResults(); + mockResults.setVersions(List.of()); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().get()) + .thenReturn(mockResults); + + Object result = template.requestBody("direct:listVersions", (Object) null); + assertEquals(mockResults, result); + } + + @Test + void testCreateGroup() throws Exception { + String endpointUri + = "apicurio-registry:newGroup?registryUrl=http://localhost:8080/apis/registry/v3&operation=createGroup"; + injectMockClient(endpointUri); + + GroupMetaData mockGroupMeta = new GroupMetaData(); + when(mockClient.groups().post(any(CreateGroup.class))).thenReturn(mockGroupMeta); + + Object result = template.requestBody("direct:createGroup", (Object) null); + assertEquals(mockGroupMeta, result); + } + + @Test + void testUpdateArtifact() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=updateArtifact"; + injectMockClient(endpointUri); + + VersionMetaData mockVersionMeta = new VersionMetaData(); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class))) + .thenReturn(mockVersionMeta); + + Object result = template.requestBody("direct:updateArtifact", "{\"updated\":true}"); + assertEquals(mockVersionMeta, result); + } + + @Test + void testOperationFromHeader() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3"; + injectMockClient(endpointUri); + + ArtifactMetaData mockMetadata = new ArtifactMetaData(); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact").get()) + .thenReturn(mockMetadata); + + Object result = template.requestBodyAndHeader("direct:operationFromHeader", null, + ApicurioRegistryConstants.HEADER_OPERATION, "getArtifactMetadata"); + assertEquals(mockMetadata, result); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java new file mode 100644 index 0000000000000..2eeb421dc4b59 --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java @@ -0,0 +1,95 @@ +/* + * 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.camel.component.apicurioregistry.integration; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.jupiter.api.Test; + +class ApicurioRegistryConsumerIT extends ApicurioRegistryTestSupport { + + private static final String JSON_SCHEMA = """ + { + "type": "object", + "properties": { + "name": {"type": "string"} + } + } + """; + + private final String groupId = "consumer-test-" + UUID.randomUUID(); + private final String artifactId = "consumer-artifact-" + UUID.randomUUID(); + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + // Producer route to create artifacts + from("direct:createForConsumer") + .toD("apicurio-registry:${header.CamelApicurioRegistryGroupId}/${header.CamelApicurioRegistryArtifactId}" + + "?registryUrl=" + getRegistryUrl()); + + // Consumer route + from("apicurio-registry:" + groupId + "/" + artifactId + + "?registryUrl=" + getRegistryUrl() + "&delay=1000") + .to("mock:consumed"); + } + }; + } + + @Test + void testConsumerReceivesNewVersions() throws Exception { + // Create the group first + Map groupHeaders = new HashMap<>(); + groupHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_GROUP); + groupHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + template.request("direct:createForConsumer", exchange -> exchange.getIn().setHeaders(groupHeaders)); + + // Create the artifact + Map createHeaders = new HashMap<>(); + createHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_ARTIFACT); + createHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, "JSON"); + createHeaders.put(ApicurioRegistryConstants.HEADER_IF_EXISTS, "FIND_OR_CREATE_VERSION"); + template.request("direct:createForConsumer", exchange -> { + exchange.getIn().setHeaders(createHeaders); + exchange.getIn().setBody(JSON_SCHEMA); + }); + + MockEndpoint mock = getMockEndpoint("mock:consumed"); + mock.expectedMinimumMessageCount(1); + MockEndpoint.assertIsSatisfied(context, 30, TimeUnit.SECONDS); + + // Verify headers set by consumer + Map receivedHeaders = mock.getReceivedExchanges().get(0).getIn().getHeaders(); + assertEquals(groupId, receivedHeaders.get(ApicurioRegistryConstants.HEADER_GROUP_ID)); + assertEquals(artifactId, receivedHeaders.get(ApicurioRegistryConstants.HEADER_ARTIFACT_ID)); + } + + private void assertEquals(Object expected, Object actual) { + org.junit.jupiter.api.Assertions.assertEquals(expected, actual); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java new file mode 100644 index 0000000000000..1cab39009d65e --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java @@ -0,0 +1,212 @@ +/* + * 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.camel.component.apicurioregistry.integration; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import io.apicurio.registry.rest.client.models.ArtifactMetaData; +import io.apicurio.registry.rest.client.models.CreateArtifactResponse; +import io.apicurio.registry.rest.client.models.GroupMetaData; +import io.apicurio.registry.rest.client.models.VersionMetaData; +import io.apicurio.registry.rest.client.models.VersionSearchResults; +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ApicurioRegistryProducerIT extends ApicurioRegistryTestSupport { + + private static final String JSON_SCHEMA = """ + { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"} + } + } + """; + + private static final String JSON_SCHEMA_V2 = """ + { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"}, + "email": {"type": "string"} + } + } + """; + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:operation") + .toD("apicurio-registry:${header.CamelApicurioRegistryGroupId}/${header.CamelApicurioRegistryArtifactId}" + + "?registryUrl=" + getRegistryUrl()); + } + }; + } + + @Test + void testFullArtifactLifecycle() throws Exception { + String groupId = "test-group-" + UUID.randomUUID(); + String artifactId = "test-artifact-" + UUID.randomUUID(); + + // 1. Create group + Map headers = new HashMap<>(); + headers.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_GROUP); + headers.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + Exchange groupResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(headers); + }); + assertNotNull(groupResult.getIn().getBody()); + assertInstanceOf(GroupMetaData.class, groupResult.getIn().getBody()); + + // 2. Create artifact + Map createHeaders = new HashMap<>(); + createHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_ARTIFACT); + createHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, "JSON"); + createHeaders.put(ApicurioRegistryConstants.HEADER_IF_EXISTS, "FIND_OR_CREATE_VERSION"); + Exchange createResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(createHeaders); + exchange.getIn().setBody(JSON_SCHEMA); + }); + assertNotNull(createResult.getIn().getBody()); + assertInstanceOf(CreateArtifactResponse.class, createResult.getIn().getBody()); + + // 3. Get artifact metadata + Map getMetaHeaders = new HashMap<>(); + getMetaHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, + ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_METADATA); + getMetaHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + getMetaHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + Exchange metaResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(getMetaHeaders); + }); + assertInstanceOf(ArtifactMetaData.class, metaResult.getIn().getBody()); + ArtifactMetaData metadata = (ArtifactMetaData) metaResult.getIn().getBody(); + assertEquals(artifactId, metadata.getArtifactId()); + + // 4. Get artifact content + Map getContentHeaders = new HashMap<>(); + getContentHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, + ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_CONTENT); + getContentHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + getContentHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + Exchange contentResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(getContentHeaders); + }); + Object contentBody = contentResult.getIn().getBody(); + assertNotNull(contentBody); + String contentStr; + if (contentBody instanceof InputStream) { + contentStr = new String(((InputStream) contentBody).readAllBytes(), StandardCharsets.UTF_8); + } else { + contentStr = contentBody.toString(); + } + assertTrue(contentStr.contains("name")); + + // 5. Update artifact (new version) + Map updateHeaders = new HashMap<>(); + updateHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, + ApicurioRegistryConstants.OPERATION_UPDATE_ARTIFACT); + updateHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + updateHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + Exchange updateResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(updateHeaders); + exchange.getIn().setBody(JSON_SCHEMA_V2); + }); + assertInstanceOf(VersionMetaData.class, updateResult.getIn().getBody()); + + // 6. List versions + Map listHeaders = new HashMap<>(); + listHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, + ApicurioRegistryConstants.OPERATION_LIST_VERSIONS); + listHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + listHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + Exchange listResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(listHeaders); + }); + assertInstanceOf(VersionSearchResults.class, listResult.getIn().getBody()); + VersionSearchResults versions = (VersionSearchResults) listResult.getIn().getBody(); + assertTrue(versions.getCount() >= 2); + + // 7. Delete artifact + Map deleteHeaders = new HashMap<>(); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, + ApicurioRegistryConstants.OPERATION_DELETE_ARTIFACT); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(deleteHeaders); + }); + } + + @Test + void testSearchArtifacts() throws Exception { + String groupId = "search-group-" + UUID.randomUUID(); + String artifactId = "search-artifact-" + UUID.randomUUID(); + + // Create group first + Map groupHeaders = new HashMap<>(); + groupHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_GROUP); + groupHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + template.request("direct:operation", exchange -> exchange.getIn().setHeaders(groupHeaders)); + + // Create artifact + Map createHeaders = new HashMap<>(); + createHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_ARTIFACT); + createHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, "JSON"); + template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(createHeaders); + exchange.getIn().setBody(JSON_SCHEMA); + }); + + // Search + Map searchHeaders = new HashMap<>(); + searchHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_SEARCH_ARTIFACTS); + searchHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + searchHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + Exchange searchResult = template.request("direct:operation", exchange -> { + exchange.getIn().setHeaders(searchHeaders); + }); + assertNotNull(searchResult.getIn().getBody()); + + // Cleanup + Map deleteHeaders = new HashMap<>(); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_DELETE_ARTIFACT); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + deleteHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + template.request("direct:operation", exchange -> exchange.getIn().setHeaders(deleteHeaders)); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryTestSupport.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryTestSupport.java new file mode 100644 index 0000000000000..f79a08f63f50c --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryTestSupport.java @@ -0,0 +1,41 @@ +/* + * 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.camel.component.apicurioregistry.integration; + +import org.apache.camel.BindToRegistry; +import org.apache.camel.component.apicurioregistry.ApicurioRegistryComponent; +import org.apache.camel.test.infra.apicurio.registry.services.ApicurioRegistryService; +import org.apache.camel.test.infra.apicurio.registry.services.ApicurioRegistryServiceFactory; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class ApicurioRegistryTestSupport extends CamelTestSupport { + + @RegisterExtension + public static ApicurioRegistryService service = ApicurioRegistryServiceFactory.createService(); + + @BindToRegistry("apicurio-registry") + public ApicurioRegistryComponent getApicurioRegistryComponent() { + ApicurioRegistryComponent component = new ApicurioRegistryComponent(); + component.getConfiguration().setRegistryUrl(service.getApicurioRegistryUrl()); + return component; + } + + protected String getRegistryUrl() { + return service.getApicurioRegistryUrl(); + } +} diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java new file mode 100644 index 0000000000000..c615eb8321831 --- /dev/null +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java @@ -0,0 +1,132 @@ +/* + * 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.camel.component.apicurioregistry.integration; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.camel.Exchange; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ApicurioRegistryValidateIT extends ApicurioRegistryTestSupport { + + private static final String JSON_SCHEMA = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"} + }, + "required": ["name"] + } + """; + + private final String groupId = "validate-group-" + UUID.randomUUID(); + private final String artifactId = "validate-artifact-" + UUID.randomUUID(); + + @Override + protected RoutesBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:setup") + .toD("apicurio-registry:${header.CamelApicurioRegistryGroupId}/${header.CamelApicurioRegistryArtifactId}" + + "?registryUrl=" + getRegistryUrl()); + + from("direct:validate") + .to("apicurio-registry:" + groupId + "/" + artifactId + + "?registryUrl=" + getRegistryUrl() + + "&operation=validate&failOnValidation=false"); + + from("direct:testCompatibility") + .to("apicurio-registry:" + groupId + "/" + artifactId + + "?registryUrl=" + getRegistryUrl() + + "&operation=testCompatibility"); + } + }; + } + + @BeforeEach + void setupArtifact() { + // Create group + Map groupHeaders = new HashMap<>(); + groupHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_GROUP); + groupHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + template.request("direct:setup", exchange -> exchange.getIn().setHeaders(groupHeaders)); + + // Create artifact with JSON Schema + Map createHeaders = new HashMap<>(); + createHeaders.put(ApicurioRegistryConstants.HEADER_OPERATION, ApicurioRegistryConstants.OPERATION_CREATE_ARTIFACT); + createHeaders.put(ApicurioRegistryConstants.HEADER_GROUP_ID, groupId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_ID, artifactId); + createHeaders.put(ApicurioRegistryConstants.HEADER_ARTIFACT_TYPE, "JSON"); + createHeaders.put(ApicurioRegistryConstants.HEADER_IF_EXISTS, "FIND_OR_CREATE_VERSION"); + template.request("direct:setup", exchange -> { + exchange.getIn().setHeaders(createHeaders); + exchange.getIn().setBody(JSON_SCHEMA); + }); + } + + @Test + void testValidateCompatibleContent() { + String compatibleSchema = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"}, + "email": {"type": "string"} + }, + "required": ["name"] + } + """; + + Exchange result = template.request("direct:validate", exchange -> { + exchange.getIn().setBody(compatibleSchema); + }); + + assertNotNull(result.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT)); + } + + @Test + void testTestCompatibility() { + String compatibleSchema = """ + { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"} + } + } + """; + + Exchange result = template.request("direct:testCompatibility", exchange -> { + exchange.getIn().setBody(compatibleSchema); + }); + + assertNotNull(result.getIn().getBody()); + } +} diff --git a/components/pom.xml b/components/pom.xml index 6e31921eb995a..bfe64674636fc 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -81,6 +81,7 @@ camel-activemq6 camel-ai camel-amqp + camel-apicurio-registry camel-arangodb camel-as2 camel-asn1 diff --git a/parent/pom.xml b/parent/pom.xml index 74182c09ed747..74b381aa5fc4d 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -724,6 +724,11 @@ camel-amqp ${project.version} + + org.apache.camel + camel-apicurio-registry + ${project.version} + org.apache.camel camel-arangodb diff --git a/test-infra/camel-test-infra-apicurio-registry/pom.xml b/test-infra/camel-test-infra-apicurio-registry/pom.xml new file mode 100644 index 0000000000000..5114b2b8f7e36 --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/pom.xml @@ -0,0 +1,41 @@ + + + + + camel-test-infra-parent + org.apache.camel + ../camel-test-infra-parent/pom.xml + 4.22.0-SNAPSHOT + + + 4.0.0 + + camel-test-infra-apicurio-registry + Camel :: Test Infra :: Apicurio Registry + + + + org.apache.camel + camel-test-infra-common + ${project.version} + + + + diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/common/ApicurioRegistryProperties.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/common/ApicurioRegistryProperties.java new file mode 100644 index 0000000000000..d73943ed709d7 --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/common/ApicurioRegistryProperties.java @@ -0,0 +1,28 @@ +/* + * 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.camel.test.infra.apicurio.registry.common; + +public final class ApicurioRegistryProperties { + public static final String APICURIO_REGISTRY_URL = "apicurio.registry.url"; + public static final String APICURIO_REGISTRY_HOST = "apicurio.registry.host"; + public static final String APICURIO_REGISTRY_PORT = "apicurio.registry.port"; + public static final String APICURIO_REGISTRY_CONTAINER = "apicurio.registry.container"; + public static final int DEFAULT_PORT = 8080; + + private ApicurioRegistryProperties() { + } +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryInfraService.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryInfraService.java new file mode 100644 index 0000000000000..7a8b8380ff79a --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryInfraService.java @@ -0,0 +1,28 @@ +/* + * 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.camel.test.infra.apicurio.registry.services; + +import org.apache.camel.test.infra.common.services.InfrastructureService; + +public interface ApicurioRegistryInfraService extends InfrastructureService { + + String getApicurioRegistryUrl(); + + String host(); + + int port(); +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java new file mode 100644 index 0000000000000..e893e1875d598 --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java @@ -0,0 +1,104 @@ +/* + * 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.camel.test.infra.apicurio.registry.services; + +import org.apache.camel.spi.annotations.InfraService; +import org.apache.camel.test.infra.apicurio.registry.common.ApicurioRegistryProperties; +import org.apache.camel.test.infra.common.LocalPropertyResolver; +import org.apache.camel.test.infra.common.services.ContainerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; + +@InfraService(service = ApicurioRegistryInfraService.class, + description = "Apicurio Registry is an API/Schema registry", + serviceAlias = { "apicurio-registry" }) +public class ApicurioRegistryLocalContainerInfraService + implements ApicurioRegistryInfraService, ContainerService> { + + public static final String CONTAINER_NAME = "apicurio-registry"; + + private static final Logger LOG = LoggerFactory.getLogger(ApicurioRegistryLocalContainerInfraService.class); + + private final GenericContainer container; + + public ApicurioRegistryLocalContainerInfraService() { + this(LocalPropertyResolver.getProperty( + ApicurioRegistryLocalContainerInfraService.class, + ApicurioRegistryProperties.APICURIO_REGISTRY_CONTAINER)); + } + + public ApicurioRegistryLocalContainerInfraService(String containerName) { + container = initContainer(containerName, CONTAINER_NAME); + } + + public ApicurioRegistryLocalContainerInfraService(GenericContainer container) { + this.container = container; + } + + @SuppressWarnings("resource") + protected GenericContainer initContainer(String imageName, String containerName) { + return new GenericContainer<>(imageName) + .withNetworkAliases(containerName) + .withExposedPorts(ApicurioRegistryProperties.DEFAULT_PORT) + .waitingFor(Wait.forHttp("/health").forPort(ApicurioRegistryProperties.DEFAULT_PORT).forStatusCode(200)); + } + + @Override + public void registerProperties() { + System.setProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_URL, getApicurioRegistryUrl()); + System.setProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_HOST, host()); + System.setProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_PORT, String.valueOf(port())); + } + + @Override + public void initialize() { + LOG.info("Trying to start the Apicurio Registry container"); + container.start(); + + registerProperties(); + LOG.info("Apicurio Registry instance running at {}", getApicurioRegistryUrl()); + } + + @Override + public void shutdown() { + LOG.info("Stopping the Apicurio Registry container"); + container.stop(); + } + + @Override + public GenericContainer getContainer() { + return container; + } + + @Override + public String getApicurioRegistryUrl() { + return String.format("http://%s:%d/apis/registry/v3", host(), + container.getMappedPort(ApicurioRegistryProperties.DEFAULT_PORT)); + } + + @Override + public String host() { + return container.getHost(); + } + + @Override + public int port() { + return container.getMappedPort(ApicurioRegistryProperties.DEFAULT_PORT); + } +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryRemoteInfraService.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryRemoteInfraService.java new file mode 100644 index 0000000000000..694a3ef14cbee --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryRemoteInfraService.java @@ -0,0 +1,58 @@ +/* + * 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.camel.test.infra.apicurio.registry.services; + +import org.apache.camel.test.infra.apicurio.registry.common.ApicurioRegistryProperties; + +public class ApicurioRegistryRemoteInfraService implements ApicurioRegistryInfraService { + + @Override + public void registerProperties() { + // NO-OP + } + + @Override + public void initialize() { + registerProperties(); + } + + @Override + public void shutdown() { + // NO-OP + } + + @Override + public String getApicurioRegistryUrl() { + return System.getProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_URL); + } + + @Override + public String host() { + return System.getProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_HOST); + } + + @Override + public int port() { + String strPort = System.getProperty(ApicurioRegistryProperties.APICURIO_REGISTRY_PORT); + + if (strPort == null) { + return ApicurioRegistryProperties.DEFAULT_PORT; + } + + return Integer.parseInt(strPort); + } +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryService.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryService.java new file mode 100644 index 0000000000000..71969410a917e --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryService.java @@ -0,0 +1,23 @@ +/* + * 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.camel.test.infra.apicurio.registry.services; + +import org.apache.camel.test.infra.common.services.ContainerTestService; +import org.apache.camel.test.infra.common.services.TestService; + +public interface ApicurioRegistryService extends ApicurioRegistryInfraService, TestService, ContainerTestService { +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryServiceFactory.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryServiceFactory.java new file mode 100644 index 0000000000000..2a64be01f9aaa --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryServiceFactory.java @@ -0,0 +1,46 @@ +/* + * 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.camel.test.infra.apicurio.registry.services; + +import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder; + +public final class ApicurioRegistryServiceFactory { + + private ApicurioRegistryServiceFactory() { + } + + public static SimpleTestServiceBuilder builder() { + return new SimpleTestServiceBuilder<>("apicurio-registry"); + } + + public static ApicurioRegistryService createService() { + return builder() + .addLocalMapping(ApicurioRegistryLocalContainerTestService::new) + .addRemoteMapping(ApicurioRegistryRemoteTestService::new) + .build(); + } + + public static class ApicurioRegistryLocalContainerTestService + extends ApicurioRegistryLocalContainerInfraService + implements ApicurioRegistryService { + } + + public static class ApicurioRegistryRemoteTestService + extends ApicurioRegistryRemoteInfraService + implements ApicurioRegistryService { + } +} diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties b/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties new file mode 100644 index 0000000000000..fd927dc86382c --- /dev/null +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties @@ -0,0 +1,17 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +apicurio.registry.container=quay.io/apicurio/apicurio-registry:3.0.6 diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 83a7548d728bb..830398d120713 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -58,6 +58,7 @@ camel-test-infra-dispatch-router camel-test-infra-jdbc camel-test-infra-arangodb + camel-test-infra-apicurio-registry camel-test-infra-consul camel-test-infra-google-pubsub camel-test-infra-infinispan From 218e2c1625638698b6a6e1b05adbd92112d4d96a Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Fri, 17 Jul 2026 13:17:40 +0200 Subject: [PATCH 2/4] Use Apicurio Registry 3.3.0 container image for ITs Assisted by Claude, model: claude-opus-4-6 --- .../services/ApicurioRegistryLocalContainerInfraService.java | 3 ++- .../test/infra/apicurio/registry/services/container.properties | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java index e893e1875d598..103e6403297c1 100644 --- a/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/java/org/apache/camel/test/infra/apicurio/registry/services/ApicurioRegistryLocalContainerInfraService.java @@ -56,7 +56,8 @@ protected GenericContainer initContainer(String imageName, String containerNa return new GenericContainer<>(imageName) .withNetworkAliases(containerName) .withExposedPorts(ApicurioRegistryProperties.DEFAULT_PORT) - .waitingFor(Wait.forHttp("/health").forPort(ApicurioRegistryProperties.DEFAULT_PORT).forStatusCode(200)); + .waitingFor(Wait.forHttp("/apis/registry/v3/system/info") + .forPort(ApicurioRegistryProperties.DEFAULT_PORT).forStatusCode(200)); } @Override diff --git a/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties b/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties index fd927dc86382c..a153fd2fe64c6 100644 --- a/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties +++ b/test-infra/camel-test-infra-apicurio-registry/src/main/resources/org/apache/camel/test/infra/apicurio/registry/services/container.properties @@ -14,4 +14,4 @@ ## See the License for the specific language governing permissions and ## limitations under the License. ## --------------------------------------------------------------------------- -apicurio.registry.container=quay.io/apicurio/apicurio-registry:3.0.6 +apicurio.registry.container=quay.io/apicurio/apicurio-registry:3.3.0 From e4ee63fdb12b65aabf58facd29375ebf37953912 Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Wed, 19 Aug 2026 13:23:35 +0200 Subject: [PATCH 3/4] Address review feedback on camel-apicurio-registry - Remove unused cacheTtl option and HEADER_DRY_RUN constant - Sort versions by globalId before processing in consumer - Convert InputStream to byte[] in getArtifactContent to avoid leaks - Extract shared doDryRun helper for testCompatibility/validate - Catch only ApiException in dry-run operations, rethrow others - Move apicurio-registry-sdk-version property to parent/pom.xml - Document consumer first-start replay behavior in .adoc - Add unit tests for searchArtifacts, testCompatibility, validate - Add consumer unit test for out-of-order globalId sorting - Improve validate IT assertions Assisted by Claude, model: claude-opus-4-6 --- components/camel-apicurio-registry/pom.xml | 4 - .../ApicurioRegistryComponentConfigurer.java | 6 - .../ApicurioRegistryEndpointConfigurer.java | 6 - .../ApicurioRegistryEndpointUriFactory.java | 3 +- .../apicurioregistry/apicurio-registry.json | 91 ++++++++------- .../docs/apicurio-registry-component.adoc | 4 + .../ApicurioRegistryConfiguration.java | 13 --- .../ApicurioRegistryConstants.java | 3 - .../ApicurioRegistryConsumer.java | 18 +-- .../ApicurioRegistryProducer.java | 58 +++++----- .../ApicurioRegistryConsumerTest.java | 41 +++++++ .../ApicurioRegistryProducerTest.java | 104 ++++++++++++++++++ .../ApicurioRegistryConsumerIT.java | 5 +- .../ApicurioRegistryValidateIT.java | 5 +- parent/pom.xml | 1 + 15 files changed, 235 insertions(+), 127 deletions(-) diff --git a/components/camel-apicurio-registry/pom.xml b/components/camel-apicurio-registry/pom.xml index 6745134f6042c..616536bfd200d 100644 --- a/components/camel-apicurio-registry/pom.xml +++ b/components/camel-apicurio-registry/pom.xml @@ -33,10 +33,6 @@ Camel :: Apicurio Registry Camel Apicurio Registry component - - 3.3.0 - - diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java index 4f83f5274502f..f994d7b5f094e 100644 --- a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryComponentConfigurer.java @@ -38,8 +38,6 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; - case "cachettl": - case "cacheTtl": getOrCreateConfiguration(target).setCacheTtl(property(camelContext, long.class, value)); return true; case "clientid": case "clientId": getOrCreateConfiguration(target).setClientId(property(camelContext, java.lang.String.class, value)); return true; case "clientsecret": @@ -76,8 +74,6 @@ public Class getOptionType(String name, boolean ignoreCase) { case "autowiredEnabled": return boolean.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; - case "cachettl": - case "cacheTtl": return long.class; case "clientid": case "clientId": return java.lang.String.class; case "clientsecret": @@ -115,8 +111,6 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "autowiredEnabled": return target.isAutowiredEnabled(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); - case "cachettl": - case "cacheTtl": return getOrCreateConfiguration(target).getCacheTtl(); case "clientid": case "clientId": return getOrCreateConfiguration(target).getClientId(); case "clientsecret": diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java index e4916994a870b..a82585a675887 100644 --- a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointConfigurer.java @@ -35,8 +35,6 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj case "backoffMultiplier": target.setBackoffMultiplier(property(camelContext, int.class, value)); return true; case "bridgeerrorhandler": case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; - case "cachettl": - case "cacheTtl": target.getConfiguration().setCacheTtl(property(camelContext, long.class, value)); return true; case "clientid": case "clientId": target.getConfiguration().setClientId(property(camelContext, java.lang.String.class, value)); return true; case "clientsecret": @@ -105,8 +103,6 @@ public Class getOptionType(String name, boolean ignoreCase) { case "backoffMultiplier": return int.class; case "bridgeerrorhandler": case "bridgeErrorHandler": return boolean.class; - case "cachettl": - case "cacheTtl": return long.class; case "clientid": case "clientId": return java.lang.String.class; case "clientsecret": @@ -176,8 +172,6 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) { case "backoffMultiplier": return target.getBackoffMultiplier(); case "bridgeerrorhandler": case "bridgeErrorHandler": return target.isBridgeErrorHandler(); - case "cachettl": - case "cacheTtl": return target.getConfiguration().getCacheTtl(); case "clientid": case "clientId": return target.getConfiguration().getClientId(); case "clientsecret": diff --git a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java index 90577aab7f31e..e2db8a74a3fca 100644 --- a/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java +++ b/components/camel-apicurio-registry/src/generated/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryEndpointUriFactory.java @@ -24,7 +24,7 @@ public class ApicurioRegistryEndpointUriFactory extends org.apache.camel.support private static final Set ENDPOINT_IDENTITY_PROPERTY_NAMES; private static final Map MULTI_VALUE_PREFIXES; static { - Set props = new HashSet<>(37); + Set props = new HashSet<>(36); props.add("artifactId"); props.add("artifactType"); props.add("authType"); @@ -32,7 +32,6 @@ public class ApicurioRegistryEndpointUriFactory extends org.apache.camel.support props.add("backoffIdleThreshold"); props.add("backoffMultiplier"); props.add("bridgeErrorHandler"); - props.add("cacheTtl"); props.add("clientId"); props.add("clientSecret"); props.add("delay"); diff --git a/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json b/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json index 82bea993998e5..13430aac6a642 100644 --- a/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json +++ b/components/camel-apicurio-registry/src/generated/resources/META-INF/org/apache/camel/component/apicurioregistry/apicurio-registry.json @@ -28,20 +28,19 @@ "bridgeErrorHandler": { "index": 1, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." }, "fetchContent": { "index": 2, "kind": "property", "displayName": "Fetch Content", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to fetch the content for each new version found by the consumer" }, "artifactType": { "index": 3, "kind": "property", "displayName": "Artifact Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "JSON", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The default artifact type" }, - "cacheTtl": { "index": 4, "kind": "property", "displayName": "Cache Ttl", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 300000, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Schema cache TTL in milliseconds for the validate operation. 0 means no caching." }, - "failOnValidation": { "index": 5, "kind": "property", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, - "ifExists": { "index": 6, "kind": "property", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, - "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "operation": { "index": 8, "kind": "property", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, - "autowiredEnabled": { "index": 9, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, - "configuration": { "index": 10, "kind": "property", "displayName": "Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The component configuration" }, - "authType": { "index": 11, "kind": "property", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, - "clientId": { "index": 12, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, - "clientSecret": { "index": 13, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, - "password": { "index": 14, "kind": "property", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, - "scope": { "index": 15, "kind": "property", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, - "tokenEndpoint": { "index": 16, "kind": "property", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, - "username": { "index": 17, "kind": "property", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } + "failOnValidation": { "index": 4, "kind": "property", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, + "ifExists": { "index": 5, "kind": "property", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, + "lazyStartProducer": { "index": 6, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "operation": { "index": 7, "kind": "property", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, + "autowiredEnabled": { "index": 8, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." }, + "configuration": { "index": 9, "kind": "property", "displayName": "Configuration", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The component configuration" }, + "authType": { "index": 10, "kind": "property", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, + "clientId": { "index": 11, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, + "clientSecret": { "index": 12, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, + "password": { "index": 13, "kind": "property", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, + "scope": { "index": 14, "kind": "property", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, + "tokenEndpoint": { "index": 15, "kind": "property", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, + "username": { "index": 16, "kind": "property", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } }, "headers": { "CamelApicurioRegistryOperation": { "index": 0, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_OPERATION" }, @@ -53,12 +52,11 @@ "CamelApicurioRegistryArtifactDescription": { "index": 6, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The artifact description", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_ARTIFACT_DESCRIPTION" }, "CamelApicurioRegistryIfExists": { "index": 7, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Behavior when artifact already exists (FAIL, CREATE_VERSION, FIND_OR_CREATE_VERSION)", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_IF_EXISTS" }, "CamelApicurioRegistryContentType": { "index": 8, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content type of the artifact", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_CONTENT_TYPE" }, - "CamelApicurioRegistryDryRun": { "index": 9, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether the operation is a dry run", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_DRY_RUN" }, - "CamelApicurioRegistryGlobalId": { "index": 10, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version global ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_GLOBAL_ID" }, - "CamelApicurioRegistryContentId": { "index": 11, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_CONTENT_ID" }, - "CamelApicurioRegistryVersionState": { "index": 12, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version state", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VERSION_STATE" }, - "CamelApicurioRegistryValidationResult": { "index": 13, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether validation passed", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_RESULT" }, - "CamelApicurioRegistryValidationErrors": { "index": 14, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Validation error details", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_ERRORS" } + "CamelApicurioRegistryGlobalId": { "index": 9, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version global ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_GLOBAL_ID" }, + "CamelApicurioRegistryContentId": { "index": 10, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "Long", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The content ID", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_CONTENT_ID" }, + "CamelApicurioRegistryVersionState": { "index": 11, "kind": "header", "displayName": "", "group": "consumer", "label": "consumer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The version state", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VERSION_STATE" }, + "CamelApicurioRegistryValidationResult": { "index": 12, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Whether validation passed", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_RESULT" }, + "CamelApicurioRegistryValidationErrors": { "index": 13, "kind": "header", "displayName": "", "group": "common", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Validation error details", "constantName": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConstants#HEADER_VALIDATION_ERRORS" } }, "properties": { "groupId": { "index": 0, "kind": "path", "displayName": "Group Id", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The artifact group ID" }, @@ -71,32 +69,31 @@ "exchangePattern": { "index": 7, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "enum", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, "pollStrategy": { "index": 8, "kind": "parameter", "displayName": "Poll Strategy", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.PollingConsumerPollStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "A pluggable org.apache.camel.PollingConsumerPollingStrategy allowing you to provide your custom implementation to control error handling usually occurred during the poll operation before an Exchange have been created and being routed in Camel." }, "artifactType": { "index": 9, "kind": "parameter", "displayName": "Artifact Type", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "JSON", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The default artifact type" }, - "cacheTtl": { "index": 10, "kind": "parameter", "displayName": "Cache Ttl", "group": "producer", "label": "producer", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 300000, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Schema cache TTL in milliseconds for the validate operation. 0 means no caching." }, - "failOnValidation": { "index": 11, "kind": "parameter", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, - "ifExists": { "index": 12, "kind": "parameter", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, - "operation": { "index": 13, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, - "lazyStartProducer": { "index": 14, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, - "registryClient": { "index": 15, "kind": "parameter", "displayName": "Registry Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.apicurio.registry.rest.client.RegistryClient", "deprecated": false, "autowired": false, "secret": false, "description": "To use a pre-configured RegistryClient instance" }, - "backoffErrorThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, - "backoffIdleThreshold": { "index": 17, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, - "backoffMultiplier": { "index": 18, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, - "delay": { "index": 19, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, - "greedy": { "index": 20, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, - "initialDelay": { "index": 21, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, - "repeatCount": { "index": 22, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, - "runLoggingLevel": { "index": 23, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, - "scheduledExecutorService": { "index": 24, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, - "scheduler": { "index": 25, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, - "schedulerProperties": { "index": 26, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, - "startScheduler": { "index": 27, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, - "timeUnit": { "index": 28, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, - "useFixedDelay": { "index": 29, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, - "authType": { "index": 30, "kind": "parameter", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, - "clientId": { "index": 31, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, - "clientSecret": { "index": 32, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, - "password": { "index": 33, "kind": "parameter", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, - "scope": { "index": 34, "kind": "parameter", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, - "tokenEndpoint": { "index": 35, "kind": "parameter", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, - "username": { "index": 36, "kind": "parameter", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } + "failOnValidation": { "index": 10, "kind": "parameter", "displayName": "Fail On Validation", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Whether to throw an exception on validation failure (validate operation). When false, sets result headers instead." }, + "ifExists": { "index": 11, "kind": "parameter", "displayName": "If Exists", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "FAIL", "CREATE_VERSION", "FIND_OR_CREATE_VERSION" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "FAIL", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Behavior when artifact already exists" }, + "operation": { "index": 12, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "createArtifact", "updateArtifact", "deleteArtifact", "getArtifactContent", "getArtifactMetadata", "searchArtifacts", "listVersions", "createGroup", "testCompatibility", "validate" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The operation to perform" }, + "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing." }, + "registryClient": { "index": 14, "kind": "parameter", "displayName": "Registry Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "io.apicurio.registry.rest.client.RegistryClient", "deprecated": false, "autowired": false, "secret": false, "description": "To use a pre-configured RegistryClient instance" }, + "backoffErrorThreshold": { "index": 15, "kind": "parameter", "displayName": "Backoff Error Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent error polls (failed due some error) that should happen before the backoffMultipler should kick-in." }, + "backoffIdleThreshold": { "index": 16, "kind": "parameter", "displayName": "Backoff Idle Threshold", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "The number of subsequent idle polls that should happen before the backoffMultipler should kick-in." }, + "backoffMultiplier": { "index": 17, "kind": "parameter", "displayName": "Backoff Multiplier", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "description": "To let the scheduled polling consumer backoff if there has been a number of subsequent idles\/errors in a row. The multiplier is then the number of polls that will be skipped before the next actual attempt is happening again. When this option is in use then backoffIdleThreshold and\/or backoffErrorThreshold must also be configured." }, + "delay": { "index": 18, "kind": "parameter", "displayName": "Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "description": "Milliseconds before the next poll." }, + "greedy": { "index": 19, "kind": "parameter", "displayName": "Greedy", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If greedy is enabled, then the ScheduledPollConsumer will run immediately again, if the previous run polled 1 or more messages." }, + "initialDelay": { "index": 20, "kind": "parameter", "displayName": "Initial Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1000, "description": "Milliseconds before the first poll starts." }, + "repeatCount": { "index": 21, "kind": "parameter", "displayName": "Repeat Count", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Specifies a maximum limit of number of fires. So if you set it to 1, the scheduler will only fire once. If you set it to 5, it will only fire five times. A value of zero or negative means fire forever." }, + "runLoggingLevel": { "index": 22, "kind": "parameter", "displayName": "Run Logging Level", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "org.apache.camel.LoggingLevel", "enum": [ "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "TRACE", "description": "The consumer logs a start\/complete log line when it polls. This option allows you to configure the logging level for that." }, + "scheduledExecutorService": { "index": 23, "kind": "parameter", "displayName": "Scheduled Executor Service", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.concurrent.ScheduledExecutorService", "deprecated": false, "autowired": false, "secret": false, "description": "Allows for configuring a custom\/shared thread pool to use for the consumer. By default each consumer has its own single threaded thread pool." }, + "scheduler": { "index": 24, "kind": "parameter", "displayName": "Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.lang.Object", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "description": "To use a cron scheduler from either camel-spring or camel-quartz component. Use value spring or quartz for built in scheduler" }, + "schedulerProperties": { "index": 25, "kind": "parameter", "displayName": "Scheduler Properties", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "object", "javaType": "java.util.Map", "prefix": "scheduler.", "multiValue": true, "deprecated": false, "autowired": false, "secret": false, "description": "To configure additional properties when using a custom scheduler or any of the Quartz, Spring based scheduler. This is a multi-value option with prefix: scheduler." }, + "startScheduler": { "index": 26, "kind": "parameter", "displayName": "Start Scheduler", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the scheduler should be auto started." }, + "timeUnit": { "index": 27, "kind": "parameter", "displayName": "Time Unit", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "enum", "javaType": "java.util.concurrent.TimeUnit", "enum": [ "NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "MILLISECONDS", "description": "Time unit for initialDelay and delay options." }, + "useFixedDelay": { "index": 28, "kind": "parameter", "displayName": "Use Fixed Delay", "group": "scheduler", "label": "consumer,scheduler", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details." }, + "authType": { "index": 29, "kind": "parameter", "displayName": "Auth Type", "group": "security", "label": "security", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "none", "basic", "oidc" ], "deprecated": false, "autowired": false, "secret": false, "defaultValue": "none", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "The authentication type to use" }, + "clientId": { "index": 30, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client ID" }, + "clientSecret": { "index": 31, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 client secret" }, + "password": { "index": 32, "kind": "parameter", "displayName": "Password", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Password for basic authentication" }, + "scope": { "index": 33, "kind": "parameter", "displayName": "Scope", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 scope" }, + "tokenEndpoint": { "index": 34, "kind": "parameter", "displayName": "Token Endpoint", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "OAuth2 token endpoint URL" }, + "username": { "index": 35, "kind": "parameter", "displayName": "Username", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.apicurioregistry.ApicurioRegistryConfiguration", "configurationField": "configuration", "description": "Username for basic authentication" } } } diff --git a/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc b/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc index 950f4c6e8c3c9..2759669156c04 100644 --- a/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc +++ b/components/camel-apicurio-registry/src/main/docs/apicurio-registry-component.adoc @@ -73,6 +73,10 @@ The consumer polls the registry for new versions of the specified artifact. It t seen `globalId` and only delivers new versions. Set the `delay` option to control the polling interval (default: 500ms). +On first start, all existing versions of the artifact are emitted as exchanges. Subsequent polls +only deliver versions created after the consumer started. The watermark is held in memory and +resets on route/context restart. + When `fetchContent=true`, the consumer fetches the version content and sets it as the exchange body. Otherwise, the version metadata object is set as the body. diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java index 99f3091e81a80..e69967e66814d 100644 --- a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConfiguration.java @@ -74,11 +74,6 @@ public class ApicurioRegistryConfiguration implements Cloneable { defaultValue = "true") private boolean failOnValidation = true; - @UriParam(label = "producer", - description = "Schema cache TTL in milliseconds for the validate operation. 0 means no caching.", - defaultValue = "300000") - private long cacheTtl = 300000; - public String getRegistryUrl() { return registryUrl; } @@ -183,14 +178,6 @@ public void setFailOnValidation(boolean failOnValidation) { this.failOnValidation = failOnValidation; } - public long getCacheTtl() { - return cacheTtl; - } - - public void setCacheTtl(long cacheTtl) { - this.cacheTtl = cacheTtl; - } - public ApicurioRegistryConfiguration copy() { try { return (ApicurioRegistryConfiguration) super.clone(); diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java index f190390be696f..00e669dbdf5f0 100644 --- a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConstants.java @@ -48,9 +48,6 @@ public interface ApicurioRegistryConstants { @Metadata(description = "The content type of the artifact", javaType = "String") String HEADER_CONTENT_TYPE = "CamelApicurioRegistryContentType"; - @Metadata(description = "Whether the operation is a dry run", javaType = "Boolean") - String HEADER_DRY_RUN = "CamelApicurioRegistryDryRun"; - @Metadata(label = "consumer", description = "The version global ID", javaType = "Long") String HEADER_GLOBAL_ID = "CamelApicurioRegistryGlobalId"; diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java index 07842bfd796ff..9e49b9273054c 100644 --- a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumer.java @@ -17,6 +17,8 @@ package org.apache.camel.component.apicurioregistry; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import io.apicurio.registry.rest.client.RegistryClient; @@ -58,7 +60,9 @@ protected int poll() throws Exception { return 0; } - List versions = results.getVersions(); + List versions = new ArrayList<>(results.getVersions()); + versions.sort(Comparator.comparingLong(SearchedVersion::getGlobalId)); + int count = 0; for (SearchedVersion version : versions) { Long globalId = version.getGlobalId(); @@ -78,19 +82,17 @@ protected int poll() throws Exception { } if (configuration.isFetchContent()) { - InputStream content = client.groups().byGroupId(groupId).artifacts() + try (InputStream content = client.groups().byGroupId(groupId).artifacts() .byArtifactId(artifactId).versions() - .byVersionExpression(version.getVersion()).content().get(); - message.setBody(content); + .byVersionExpression(version.getVersion()).content().get()) { + message.setBody(content.readAllBytes()); + } } else { message.setBody(version); } getProcessor().process(exchange); - - if (lastSeenGlobalId == null || globalId > lastSeenGlobalId) { - lastSeenGlobalId = globalId; - } + lastSeenGlobalId = globalId; count++; } } diff --git a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java index 13b5face56ed1..8dcb56d33c52b 100644 --- a/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java +++ b/components/camel-apicurio-registry/src/main/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducer.java @@ -18,6 +18,7 @@ import java.io.InputStream; +import com.microsoft.kiota.ApiException; import io.apicurio.registry.rest.client.RegistryClient; import io.apicurio.registry.rest.client.models.ArtifactMetaData; import io.apicurio.registry.rest.client.models.CreateArtifact; @@ -126,15 +127,16 @@ public void deleteArtifact(Message message) { } @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_CONTENT) - public void getArtifactContent(Message message) { + public void getArtifactContent(Message message) throws Exception { String groupId = resolveGroupId(message); String artifactId = resolveArtifactId(message); String version = message.getHeader( ApicurioRegistryConstants.HEADER_VERSION, "branch=latest", String.class); - InputStream content = getClient().groups().byGroupId(groupId).artifacts() - .byArtifactId(artifactId).versions().byVersionExpression(version).content().get(); - message.setBody(content); + try (InputStream content = getClient().groups().byGroupId(groupId).artifacts() + .byArtifactId(artifactId).versions().byVersionExpression(version).content().get()) { + message.setBody(content.readAllBytes()); + } } @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_GET_ARTIFACT_METADATA) @@ -192,32 +194,26 @@ public void createGroup(Message message) { } @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_TEST_COMPATIBILITY) - public void testCompatibility(Message message) { - String groupId = resolveGroupId(message); - String artifactId = resolveArtifactId(message); - String content = message.getBody(String.class); - String contentType = message.getHeader( - ApicurioRegistryConstants.HEADER_CONTENT_TYPE, "application/json", String.class); - - CreateVersion createVersion = new CreateVersion(); - VersionContent vc = new VersionContent(); - vc.setContent(content); - vc.setContentType(contentType); - createVersion.setContent(vc); - - try { - getClient().groups().byGroupId(groupId).artifacts() - .byArtifactId(artifactId).versions() - .post(createVersion, config -> config.queryParameters.dryRun = true); - message.setBody(true); - } catch (Exception e) { - message.setBody(false); - message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS, e.getMessage()); - } + public void testCompatibility(Message message) throws Exception { + boolean compatible = doDryRun(message); + message.setBody(compatible); } @InvokeOnHeader(ApicurioRegistryConstants.OPERATION_VALIDATE) public void validate(Message message) throws Exception { + boolean valid = doDryRun(message); + message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, valid); + if (!valid && configuration.isFailOnValidation()) { + String errors = message.getHeader( + ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS, String.class); + String groupId = resolveGroupId(message); + String artifactId = resolveArtifactId(message); + throw new ApicurioRegistryValidationException( + "Validation failed for artifact " + groupId + "/" + artifactId, errors); + } + } + + private boolean doDryRun(Message message) throws Exception { String groupId = resolveGroupId(message); String artifactId = resolveArtifactId(message); String content = message.getBody(String.class); @@ -234,14 +230,10 @@ public void validate(Message message) throws Exception { getClient().groups().byGroupId(groupId).artifacts() .byArtifactId(artifactId).versions() .post(createVersion, config -> config.queryParameters.dryRun = true); - message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, true); - } catch (Exception e) { - message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, false); + return true; + } catch (ApiException e) { message.setHeader(ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS, e.getMessage()); - if (configuration.isFailOnValidation()) { - throw new ApicurioRegistryValidationException( - "Validation failed for artifact " + groupId + "/" + artifactId, e.getMessage()); - } + return false; } } } diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java index 0976f3abbea35..666353064cad4 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java @@ -29,6 +29,7 @@ import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -88,6 +89,46 @@ void testPollNewVersions() throws Exception { MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); } + @Test + void testPollOutOfOrderGlobalIds() throws Exception { + injectMockClient(); + + SearchedVersion v1 = new SearchedVersion(); + v1.setGlobalId(5L); + v1.setVersion("1.0"); + v1.setContentId(100L); + v1.setArtifactType("JSON"); + + SearchedVersion v2 = new SearchedVersion(); + v2.setGlobalId(2L); + v2.setVersion("0.1"); + v2.setContentId(99L); + v2.setArtifactType("JSON"); + + SearchedVersion v3 = new SearchedVersion(); + v3.setGlobalId(8L); + v3.setVersion("2.0"); + v3.setContentId(102L); + v3.setArtifactType("JSON"); + + VersionSearchResults results = new VersionSearchResults(); + results.setVersions(List.of(v1, v2, v3)); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().get()) + .thenReturn(results); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMinimumMessageCount(3); + MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); + + // Verify exchanges arrive sorted by globalId (ascending) + List receivedIds = mock.getReceivedExchanges().stream() + .map(e -> e.getIn().getHeader(ApicurioRegistryConstants.HEADER_GLOBAL_ID, Long.class)) + .toList(); + assertEquals(List.of(2L, 5L, 8L), receivedIds); + } + @Test void testPollNoNewVersionsAfterInitial() throws Exception { injectMockClient(); diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java index 4c76854d4323b..2263ab93168eb 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryProducerTest.java @@ -20,8 +20,10 @@ import java.nio.charset.StandardCharsets; import java.util.List; +import com.microsoft.kiota.ApiException; import io.apicurio.registry.rest.client.RegistryClient; import io.apicurio.registry.rest.client.models.ArtifactMetaData; +import io.apicurio.registry.rest.client.models.ArtifactSearchResults; import io.apicurio.registry.rest.client.models.CreateArtifact; import io.apicurio.registry.rest.client.models.CreateArtifactResponse; import io.apicurio.registry.rest.client.models.CreateGroup; @@ -30,13 +32,17 @@ import io.apicurio.registry.rest.client.models.VersionMetaData; import io.apicurio.registry.rest.client.models.VersionSearchResults; import org.apache.camel.BindToRegistry; +import org.apache.camel.CamelExecutionException; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @@ -83,6 +89,15 @@ public void configure() { from("direct:searchArtifacts") .to("apicurio-registry:testGroup?registryUrl=http://localhost:8080/apis/registry/v3&operation=searchArtifacts"); + from("direct:testCompatibility") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=testCompatibility"); + + from("direct:validate") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=validate&failOnValidation=false"); + + from("direct:validateFail") + .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=validate&failOnValidation=true"); + from("direct:operationFromHeader") .to("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3"); } @@ -206,4 +221,93 @@ void testOperationFromHeader() throws Exception { ApicurioRegistryConstants.HEADER_OPERATION, "getArtifactMetadata"); assertEquals(mockMetadata, result); } + + @Test + void testSearchArtifacts() throws Exception { + String endpointUri + = "apicurio-registry:testGroup?registryUrl=http://localhost:8080/apis/registry/v3&operation=searchArtifacts"; + injectMockClient(endpointUri); + + ArtifactSearchResults mockResults = new ArtifactSearchResults(); + when(mockClient.search().artifacts().get(any())).thenReturn(mockResults); + + Object result = template.requestBody("direct:searchArtifacts", (Object) null); + assertEquals(mockResults, result); + } + + @Test + void testTestCompatibilitySuccess() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=testCompatibility"; + injectMockClient(endpointUri); + + VersionMetaData mockVersion = new VersionMetaData(); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class), any())) + .thenReturn(mockVersion); + + Object result = template.requestBody("direct:testCompatibility", "{\"test\":true}"); + assertEquals(true, result); + } + + @Test + void testTestCompatibilityFailure() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=testCompatibility"; + injectMockClient(endpointUri); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class), any())) + .thenThrow(new ApiException("incompatible")); + + Object result = template.requestBody("direct:testCompatibility", "{\"bad\":true}"); + assertEquals(false, result); + } + + @Test + void testValidateSuccess() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=validate&failOnValidation=false"; + injectMockClient(endpointUri); + + VersionMetaData mockVersion = new VersionMetaData(); + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class), any())) + .thenReturn(mockVersion); + + var exchange = template.request("direct:validate", ex -> ex.getIn().setBody("{\"test\":true}")); + assertTrue(exchange.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, Boolean.class)); + } + + @Test + void testValidateFailureNoThrow() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=validate&failOnValidation=false"; + injectMockClient(endpointUri); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class), any())) + .thenThrow(new ApiException("validation error")); + + var exchange = template.request("direct:validate", ex -> ex.getIn().setBody("{\"bad\":true}")); + assertFalse(exchange.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT, Boolean.class)); + assertNotNull(exchange.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_ERRORS)); + } + + @Test + void testValidateFailureThrows() throws Exception { + String endpointUri + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&operation=validate&failOnValidation=true"; + injectMockClient(endpointUri); + + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().post(any(CreateVersion.class), any())) + .thenThrow(new ApiException("validation error")); + + try { + template.requestBody("direct:validateFail", "{\"bad\":true}"); + } catch (CamelExecutionException e) { + assertInstanceOf(ApicurioRegistryValidationException.class, e.getCause()); + } + } } diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java index 2eeb421dc4b59..ceadda364943f 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryConsumerIT.java @@ -27,6 +27,8 @@ import org.apache.camel.component.mock.MockEndpoint; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + class ApicurioRegistryConsumerIT extends ApicurioRegistryTestSupport { private static final String JSON_SCHEMA = """ @@ -89,7 +91,4 @@ void testConsumerReceivesNewVersions() throws Exception { assertEquals(artifactId, receivedHeaders.get(ApicurioRegistryConstants.HEADER_ARTIFACT_ID)); } - private void assertEquals(Object expected, Object actual) { - org.junit.jupiter.api.Assertions.assertEquals(expected, actual); - } } diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java index c615eb8321831..d8eeda7414227 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryValidateIT.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; class ApicurioRegistryValidateIT extends ApicurioRegistryTestSupport { @@ -108,7 +109,7 @@ void testValidateCompatibleContent() { exchange.getIn().setBody(compatibleSchema); }); - assertNotNull(result.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT)); + assertEquals(true, result.getIn().getHeader(ApicurioRegistryConstants.HEADER_VALIDATION_RESULT)); } @Test @@ -127,6 +128,6 @@ void testTestCompatibility() { exchange.getIn().setBody(compatibleSchema); }); - assertNotNull(result.getIn().getBody()); + assertEquals(true, result.getIn().getBody()); } } diff --git a/parent/pom.xml b/parent/pom.xml index 74b381aa5fc4d..d4d28a4899d92 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -67,6 +67,7 @@ 2.0.5 2.0.0.AM27 1.22.0 + 3.3.0 7.26.0 5.1.7 1.12.1 From 6c5724dc840c74f0c76cd599f7e61e62de139f2f Mon Sep 17 00:00:00 2001 From: Carles Arnal Date: Wed, 19 Aug 2026 13:41:15 +0200 Subject: [PATCH 4/4] Fix consumer unit tests and producer IT after review feedback Assisted by Claude, model: claude-opus-4-6 --- .../ApicurioRegistryConsumerTest.java | 75 ++++++++++--------- .../ApicurioRegistryProducerIT.java | 10 +-- 2 files changed, 40 insertions(+), 45 deletions(-) diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java index 666353064cad4..fc8c429f718e6 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/ApicurioRegistryConsumerTest.java @@ -22,49 +22,61 @@ import io.apicurio.registry.rest.client.RegistryClient; import io.apicurio.registry.rest.client.models.SearchedVersion; import io.apicurio.registry.rest.client.models.VersionSearchResults; -import org.apache.camel.BindToRegistry; -import org.apache.camel.RoutesBuilder; +import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.impl.DefaultCamelContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -class ApicurioRegistryConsumerTest extends CamelTestSupport { +class ApicurioRegistryConsumerTest { + + private static final String ENDPOINT_URI + = "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=500"; private final RegistryClient mockClient = mock(RegistryClient.class, org.mockito.Mockito.RETURNS_DEEP_STUBS); + private CamelContext context; - @BindToRegistry("apicurio-registry") - public ApicurioRegistryComponent getComponent() { + @BeforeEach + void setUp() { + context = new DefaultCamelContext(); ApicurioRegistryComponent component = new ApicurioRegistryComponent(context); component.getConfiguration().setRegistryUrl("http://localhost:8080/apis/registry/v3"); - return component; + context.addComponent("apicurio-registry", component); + } + + @AfterEach + void tearDown() throws Exception { + if (context != null) { + context.stop(); + } } - @Override - protected RoutesBuilder createRouteBuilder() { - return new RouteBuilder() { + private void setupAndStartRoute(VersionSearchResults results) throws Exception { + when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") + .versions().get()) + .thenReturn(results); + + ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint(ENDPOINT_URI); + endpoint.setRegistryClient(mockClient); + + context.addRoutes(new RouteBuilder() { @Override public void configure() { - from("apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=500") - .to("mock:result"); + from(ENDPOINT_URI).to("mock:result"); } - }; - } + }); - private void injectMockClient() { - ApicurioRegistryEndpoint endpoint = (ApicurioRegistryEndpoint) context.getEndpoint( - "apicurio-registry:testGroup/testArtifact?registryUrl=http://localhost:8080/apis/registry/v3&delay=500"); - endpoint.setRegistryClient(mockClient); + context.start(); } @Test void testPollNewVersions() throws Exception { - injectMockClient(); - SearchedVersion v1 = new SearchedVersion(); v1.setGlobalId(1L); v1.setVersion("1.0"); @@ -80,19 +92,15 @@ void testPollNewVersions() throws Exception { VersionSearchResults results = new VersionSearchResults(); results.setVersions(List.of(v1, v2)); - when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") - .versions().get()) - .thenReturn(results); + setupAndStartRoute(results); - MockEndpoint mock = getMockEndpoint("mock:result"); + MockEndpoint mock = context.getEndpoint("mock:result", MockEndpoint.class); mock.expectedMinimumMessageCount(2); MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); } @Test void testPollOutOfOrderGlobalIds() throws Exception { - injectMockClient(); - SearchedVersion v1 = new SearchedVersion(); v1.setGlobalId(5L); v1.setVersion("1.0"); @@ -114,15 +122,12 @@ void testPollOutOfOrderGlobalIds() throws Exception { VersionSearchResults results = new VersionSearchResults(); results.setVersions(List.of(v1, v2, v3)); - when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") - .versions().get()) - .thenReturn(results); + setupAndStartRoute(results); - MockEndpoint mock = getMockEndpoint("mock:result"); + MockEndpoint mock = context.getEndpoint("mock:result", MockEndpoint.class); mock.expectedMinimumMessageCount(3); MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); - // Verify exchanges arrive sorted by globalId (ascending) List receivedIds = mock.getReceivedExchanges().stream() .map(e -> e.getIn().getHeader(ApicurioRegistryConstants.HEADER_GLOBAL_ID, Long.class)) .toList(); @@ -131,8 +136,6 @@ void testPollOutOfOrderGlobalIds() throws Exception { @Test void testPollNoNewVersionsAfterInitial() throws Exception { - injectMockClient(); - SearchedVersion v1 = new SearchedVersion(); v1.setGlobalId(1L); v1.setVersion("1.0"); @@ -142,11 +145,9 @@ void testPollNoNewVersionsAfterInitial() throws Exception { VersionSearchResults results = new VersionSearchResults(); results.setVersions(List.of(v1)); - when(mockClient.groups().byGroupId("testGroup").artifacts().byArtifactId("testArtifact") - .versions().get()) - .thenReturn(results); + setupAndStartRoute(results); - MockEndpoint mock = getMockEndpoint("mock:result"); + MockEndpoint mock = context.getEndpoint("mock:result", MockEndpoint.class); mock.expectedMessageCount(1); MockEndpoint.assertIsSatisfied(context, 10, TimeUnit.SECONDS); } diff --git a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java index 1cab39009d65e..97681befadc96 100644 --- a/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java +++ b/components/camel-apicurio-registry/src/test/java/org/apache/camel/component/apicurioregistry/integration/ApicurioRegistryProducerIT.java @@ -16,7 +16,6 @@ */ package org.apache.camel.component.apicurioregistry.integration; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -124,14 +123,9 @@ void testFullArtifactLifecycle() throws Exception { Exchange contentResult = template.request("direct:operation", exchange -> { exchange.getIn().setHeaders(getContentHeaders); }); - Object contentBody = contentResult.getIn().getBody(); + byte[] contentBody = contentResult.getIn().getBody(byte[].class); assertNotNull(contentBody); - String contentStr; - if (contentBody instanceof InputStream) { - contentStr = new String(((InputStream) contentBody).readAllBytes(), StandardCharsets.UTF_8); - } else { - contentStr = contentBody.toString(); - } + String contentStr = new String(contentBody, StandardCharsets.UTF_8); assertTrue(contentStr.contains("name")); // 5. Update artifact (new version)