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..103e6403297c1
--- /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,105 @@
+/*
+ * 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("/apis/registry/v3/system/info")
+ .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..a153fd2fe64c6
--- /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.3.0
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