This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch uri-assembler in repository https://gitbox.apache.org/repos/asf/camel.git
commit b497a65a5f325b736240b6a39705bdc9db0d853e Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Sep 25 11:44:00 2020 +0200 CAMEL-15567: components - Generate source code for creating endpoint uri via a map of properties. WIP --- .../component/ahc/AhcEndpointUriAssembler.java | 12 +- .../jetty9/JettyHttp9EndpointUriAssembler.java | 12 +- .../component/log/LogEndpointUriAssembler.java} | 16 ++- .../org/apache/camel/assembler/log-endpoint | 2 + .../component/mail/MailEndpointUriAssembler.java | 39 +++++++ .../org/apache/camel/assembler/imap-endpoint | 2 + .../org/apache/camel/assembler/imaps-endpoint | 2 + .../org/apache/camel/assembler/pop3-endpoint | 2 + .../org/apache/camel/assembler/pop3s-endpoint | 2 + .../org/apache/camel/assembler/smtp-endpoint | 2 + .../org/apache/camel/assembler/smtps-endpoint | 2 + .../netty/http/NettyHttpEndpointUriAssembler.java | 18 ++- .../org/apache/camel/ExtendedCamelContext.java | 11 ++ ...intUriAssembler.java => AssemblerResolver.java} | 21 ++-- .../org/apache/camel/spi/EndpointUriAssembler.java | 5 +- .../camel/impl/engine/AbstractCamelContext.java | 28 +++-- .../impl/engine/DefaultAssemblerResolver.java | 126 +++++++++++++++++++++ .../camel/impl/engine/SimpleCamelContext.java | 6 + .../impl/CamelCatalogEndpointUriAssembler.java | 7 ++ .../camel/impl/ExtendedCamelContextConfigurer.java | 5 + .../camel/impl/lw/LightweightCamelContext.java | 11 ++ .../impl/lw/LightweightRuntimeCamelContext.java | 12 +- .../catalog/CustomEndpointUriAssemblerTest.java | 29 ++++- .../component/log/LogEndpointUriAssemblerTest.java | 31 +++++ .../apache/camel/impl/AssembleResolverTest.java | 43 +++++++ .../component/EndpointUriAssemblerSupport.java | 2 +- .../packaging/EndpointUriAssemblerGenerator.java | 51 ++++++++- 27 files changed, 454 insertions(+), 45 deletions(-) diff --git a/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java b/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java index 3e3d8ae..d2860d0 100644 --- a/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java +++ b/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java @@ -12,13 +12,19 @@ import org.apache.camel.spi.EndpointUriAssembler; */ public class AhcEndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { - private static final String SYNTAX = "ahc:httpUri"; + private static final String BASE = ":httpUri"; + + @Override + public boolean isEnabled(String scheme) { + return "ahc".equals(scheme); + } @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { - String uri = SYNTAX; + String syntax = scheme + BASE; + String uri = syntax; - uri = buildPathParameter(camelContext, SYNTAX, uri, "httpUri", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "httpUri", null, true, parameters); uri = buildQueryParameters(camelContext, uri, parameters); return uri; } diff --git a/components/camel-jetty/src/generated/java/org/apache/camel/component/jetty9/JettyHttp9EndpointUriAssembler.java b/components/camel-jetty/src/generated/java/org/apache/camel/component/jetty9/JettyHttp9EndpointUriAssembler.java index e0f4418..68943b1c 100644 --- a/components/camel-jetty/src/generated/java/org/apache/camel/component/jetty9/JettyHttp9EndpointUriAssembler.java +++ b/components/camel-jetty/src/generated/java/org/apache/camel/component/jetty9/JettyHttp9EndpointUriAssembler.java @@ -12,13 +12,19 @@ import org.apache.camel.spi.EndpointUriAssembler; */ public class JettyHttp9EndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { - private static final String SYNTAX = "jetty:httpUri"; + private static final String BASE = ":httpUri"; + + @Override + public boolean isEnabled(String scheme) { + return "jetty".equals(scheme); + } @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { - String uri = SYNTAX; + String syntax = scheme + BASE; + String uri = syntax; - uri = buildPathParameter(camelContext, SYNTAX, uri, "httpUri", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "httpUri", null, true, parameters); uri = buildQueryParameters(camelContext, uri, parameters); return uri; } diff --git a/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriAssembler.java similarity index 58% copy from components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java copy to components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriAssembler.java index 3e3d8ae..250bb46 100644 --- a/components/camel-ahc/src/generated/java/org/apache/camel/component/ahc/AhcEndpointUriAssembler.java +++ b/components/camel-log/src/generated/java/org/apache/camel/component/log/LogEndpointUriAssembler.java @@ -1,5 +1,5 @@ /* Generated by camel build tools - do NOT edit this file! */ -package org.apache.camel.component.ahc; +package org.apache.camel.component.log; import java.net.URISyntaxException; import java.util.Map; @@ -10,15 +10,21 @@ import org.apache.camel.spi.EndpointUriAssembler; /** * Generated by camel build tools - do NOT edit this file! */ -public class AhcEndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { +public class LogEndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { - private static final String SYNTAX = "ahc:httpUri"; + private static final String BASE = ":loggerName"; + + @Override + public boolean isEnabled(String scheme) { + return "log".equals(scheme); + } @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { - String uri = SYNTAX; + String syntax = scheme + BASE; + String uri = syntax; - uri = buildPathParameter(camelContext, SYNTAX, uri, "httpUri", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "loggerName", null, true, parameters); uri = buildQueryParameters(camelContext, uri, parameters); return uri; } diff --git a/components/camel-log/src/generated/resources/META-INF/services/org/apache/camel/assembler/log-endpoint b/components/camel-log/src/generated/resources/META-INF/services/org/apache/camel/assembler/log-endpoint new file mode 100644 index 0000000..f461f57 --- /dev/null +++ b/components/camel-log/src/generated/resources/META-INF/services/org/apache/camel/assembler/log-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.log.LogEndpointUriAssembler diff --git a/components/camel-mail/src/generated/java/org/apache/camel/component/mail/MailEndpointUriAssembler.java b/components/camel-mail/src/generated/java/org/apache/camel/component/mail/MailEndpointUriAssembler.java new file mode 100644 index 0000000..f5fae41 --- /dev/null +++ b/components/camel-mail/src/generated/java/org/apache/camel/component/mail/MailEndpointUriAssembler.java @@ -0,0 +1,39 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.mail; + +import java.net.URISyntaxException; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.EndpointUriAssembler; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +public class MailEndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { + + private static final String BASE = ":host:port"; + private static final String[] SCHEMES = new String[]{"imap", "imaps", "pop3", "pop3s", "smtp", "smtps"}; + + @Override + public boolean isEnabled(String scheme) { + for (String s : SCHEMES) { + if (s.equals(scheme)) { + return true; + } + } + return false; + } + + @Override + public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + uri = buildPathParameter(camelContext, syntax, uri, "host", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "port", null, false, parameters); + uri = buildQueryParameters(camelContext, uri, parameters); + return uri; + } +} + diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imap-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imap-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imap-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imaps-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imaps-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/imaps-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3s-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3s-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/pop3s-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtp-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtp-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtp-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtps-endpoint b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtps-endpoint new file mode 100644 index 0000000..500af80 --- /dev/null +++ b/components/camel-mail/src/generated/resources/META-INF/services/org/apache/camel/assembler/smtps-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.mail.MailEndpointUriAssembler diff --git a/components/camel-netty-http/src/generated/java/org/apache/camel/component/netty/http/NettyHttpEndpointUriAssembler.java b/components/camel-netty-http/src/generated/java/org/apache/camel/component/netty/http/NettyHttpEndpointUriAssembler.java index e252977..3bc4475 100644 --- a/components/camel-netty-http/src/generated/java/org/apache/camel/component/netty/http/NettyHttpEndpointUriAssembler.java +++ b/components/camel-netty-http/src/generated/java/org/apache/camel/component/netty/http/NettyHttpEndpointUriAssembler.java @@ -12,16 +12,22 @@ import org.apache.camel.spi.EndpointUriAssembler; */ public class NettyHttpEndpointUriAssembler extends org.apache.camel.support.component.EndpointUriAssemblerSupport implements EndpointUriAssembler { - private static final String SYNTAX = "netty-http:protocol:host:port/path"; + private static final String BASE = ":protocol:host:port/path"; + + @Override + public boolean isEnabled(String scheme) { + return "netty-http".equals(scheme); + } @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { - String uri = SYNTAX; + String syntax = scheme + BASE; + String uri = syntax; - uri = buildPathParameter(camelContext, SYNTAX, uri, "protocol", null, true, parameters); - uri = buildPathParameter(camelContext, SYNTAX, uri, "host", null, true, parameters); - uri = buildPathParameter(camelContext, SYNTAX, uri, "port", null, false, parameters); - uri = buildPathParameter(camelContext, SYNTAX, uri, "path", null, false, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "protocol", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "host", null, true, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "port", null, false, parameters); + uri = buildPathParameter(camelContext, syntax, uri, "path", null, false, parameters); uri = buildQueryParameters(camelContext, uri, parameters); return uri; } diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java index 4122a85..239e163 100644 --- a/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java +++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedCamelContext.java @@ -25,6 +25,7 @@ import java.util.concurrent.ScheduledExecutorService; import org.apache.camel.catalog.RuntimeCamelCatalog; import org.apache.camel.spi.AnnotationBasedProcessorFactory; +import org.apache.camel.spi.AssemblerResolver; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; import org.apache.camel.spi.BeanProcessorFactory; @@ -551,6 +552,16 @@ public interface ExtendedCamelContext extends CamelContext { void setConfigurerResolver(ConfigurerResolver configurerResolver); /** + * Gets the {@link AssemblerResolver} to use. + */ + AssemblerResolver getAssemblerResolver(); + + /** + * Sets the {@link AssemblerResolver} to use. + */ + void setAssemblerResolver(AssemblerResolver assemblerResolver); + + /** * Internal {@link RouteController} that are only used internally by Camel to perform basic route operations. Do not * use this as end user. */ diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java b/core/camel-api/src/main/java/org/apache/camel/spi/AssemblerResolver.java similarity index 59% copy from core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java copy to core/camel-api/src/main/java/org/apache/camel/spi/AssemblerResolver.java index c1ed600..7e55562 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/AssemblerResolver.java @@ -16,26 +16,19 @@ */ package org.apache.camel.spi; -import java.net.URISyntaxException; -import java.util.Map; - import org.apache.camel.CamelContext; /** - * To assemble an endpoint uri String from a map of parameters. + * A pluggable strategy for resolving different assemblers in a loosely coupled manner */ -public interface EndpointUriAssembler { - - // TODO: Consider a better name. +public interface AssemblerResolver { /** - * Assembles an endpoint uri for the given component name with the given parameters. + * Resolves the given assembler. * - * @param camelContext the Camel context - * @param scheme the component name - * @param parameters endpoint options - * @return the constructed endpoint uri + * @param name the name of the assembler (timer-endpoint etc) + * @param context the camel context + * @return the resolved assembler, or <tt>null</tt> if no assembler could be found */ - String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException; - + EndpointUriAssembler resolveAssembler(String name, CamelContext context); } diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java index c1ed600..427d526 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/EndpointUriAssembler.java @@ -26,7 +26,10 @@ import org.apache.camel.CamelContext; */ public interface EndpointUriAssembler { - // TODO: Consider a better name. + /** + * Checks whether this assembler supports the given component name + */ + boolean isEnabled(String scheme); /** * Assembles an endpoint uri for the given component name with the given parameters. diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index dd810cb..c549440 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -77,6 +77,7 @@ import org.apache.camel.impl.transformer.TransformerKey; import org.apache.camel.impl.validator.ValidatorKey; import org.apache.camel.spi.AnnotationBasedProcessorFactory; import org.apache.camel.spi.AnnotationScanTypeConverters; +import org.apache.camel.spi.AssemblerResolver; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; import org.apache.camel.spi.BeanProcessorFactory; @@ -257,6 +258,7 @@ public abstract class AbstractCamelContext extends BaseService private volatile ComponentNameResolver componentNameResolver; private volatile LanguageResolver languageResolver; private volatile ConfigurerResolver configurerResolver; + private volatile AssemblerResolver assemblerResolver; private volatile DataFormatResolver dataFormatResolver; private volatile ManagementStrategy managementStrategy; private volatile ManagementMBeanAssembler managementMBeanAssembler; @@ -1876,6 +1878,21 @@ public abstract class AbstractCamelContext extends BaseService this.configurerResolver = doAddService(configurerResolver); } + public AssemblerResolver getAssemblerResolver() { + if (assemblerResolver == null) { + synchronized (lock) { + if (assemblerResolver == null) { + setAssemblerResolver(createAssemblerResolver()); + } + } + } + return assemblerResolver; + } + + public void setAssemblerResolver(AssemblerResolver assemblerResolver) { + this.assemblerResolver = doAddService(assemblerResolver); + } + public boolean isAutoCreateComponents() { return autoCreateComponents; } @@ -3206,6 +3223,7 @@ public abstract class AbstractCamelContext extends BaseService getRegistry(); getLanguageResolver(); getConfigurerResolver(); + getAssemblerResolver(); getExecutorServiceManager(); getInflightRepository(); getAsyncProcessorAwaitManager(); @@ -4208,6 +4226,8 @@ public abstract class AbstractCamelContext extends BaseService protected abstract ConfigurerResolver createConfigurerResolver(); + protected abstract AssemblerResolver createAssemblerResolver(); + protected abstract RestRegistryFactory createRestRegistryFactory(); protected abstract EndpointRegistry<EndpointKey> createEndpointRegistry(Map<EndpointKey, Endpoint> endpoints); @@ -4237,13 +4257,7 @@ public abstract class AbstractCamelContext extends BaseService @Override public EndpointUriAssembler getEndpointUriAssembler(String scheme) { - // TODO: lookup factory specific for a given component - - // no specific factory found so lets fallback to use runtime catalog - return new BaseServiceResolver<>(RuntimeCamelCatalog.ENDPOINT_URI_ASSEMBLER_FACTORY, EndpointUriAssembler.class) - .resolve(getCamelContextReference()) - .orElseThrow(() -> new IllegalArgumentException( - "Cannot find RuntimeCamelCatalog on classpath. Add camel-core-catalog to classpath.")); + return getAssemblerResolver().resolveAssembler(scheme, this); } public enum Initialization { diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultAssemblerResolver.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultAssemblerResolver.java new file mode 100644 index 0000000..c8ffea6 --- /dev/null +++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DefaultAssemblerResolver.java @@ -0,0 +1,126 @@ +/* + * 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.impl.engine; + +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.NoFactoryAvailableException; +import org.apache.camel.spi.AssemblerResolver; +import org.apache.camel.spi.EndpointUriAssembler; +import org.apache.camel.spi.FactoryFinder; +import org.apache.camel.support.LRUCacheFactory; +import org.apache.camel.support.service.ServiceSupport; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Default assembler resolver that looks for assembler factories in + * <b>META-INF/services/org/apache/camel/assembler/</b>. + */ +public class DefaultAssemblerResolver extends ServiceSupport implements CamelContextAware, AssemblerResolver { + public static final String RESOURCE_PATH = "META-INF/services/org/apache/camel/assembler/"; + + private static final Logger LOG = LoggerFactory.getLogger(DefaultAssemblerResolver.class); + + private final Map<String, EndpointUriAssembler> cache = LRUCacheFactory.newLRUSoftCache(1000); + private CamelContext camelContext; + private FactoryFinder factoryFinder; + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public EndpointUriAssembler resolveAssembler(final String name, CamelContext context) { + if (ObjectHelper.isEmpty(name)) { + return null; + } + + EndpointUriAssembler answer = cache.get(name); + if (answer != null) { + return answer; + } + + // lookup in registry first + Set<EndpointUriAssembler> assemblers = context.getRegistry().findByType(EndpointUriAssembler.class); + answer = assemblers.stream().filter(a -> a.isEnabled(name)).findFirst().orElse(null); + if (answer != null) { + cache.put(name, answer); + return answer; + } + + // not in registry then use assembler factory for endpoints + Class<?> type; + try { + type = findAssembler(name + "-endpoint", context); + } catch (NoFactoryAvailableException e) { + // its optional so its okay + type = null; + } catch (Exception e) { + throw new IllegalArgumentException("Invalid URI, no Assembler registered for scheme: " + name, e); + } + + if (type != null) { + if (getLog().isDebugEnabled()) { + getLog().debug("Found assembler: {} via type: {} via: {}{}", name, type.getName(), + factoryFinder.getResourcePath(), + name); + } + + // create the assembler + if (EndpointUriAssembler.class.isAssignableFrom(type)) { + answer = (EndpointUriAssembler) context.getInjector().newInstance(type, false); + cache.put(name, answer); + return answer; + } else { + throw new IllegalArgumentException( + "Type is not a EndpointUriAssembler implementation. Found: " + type.getName()); + } + } + + return answer; + } + + private Class<?> findAssembler(String name, CamelContext context) throws IOException { + if (factoryFinder == null) { + factoryFinder = context.adapt(ExtendedCamelContext.class).getFactoryFinder(RESOURCE_PATH); + } + return factoryFinder.findClass(name).orElse(null); + } + + protected Logger getLog() { + return LOG; + } + + @Override + protected void doStop() throws Exception { + cache.clear(); + } + +} diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java index 952f00d..0391da8 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/SimpleCamelContext.java @@ -32,6 +32,7 @@ import org.apache.camel.impl.converter.DefaultTypeConverter; import org.apache.camel.impl.transformer.TransformerKey; import org.apache.camel.impl.validator.ValidatorKey; import org.apache.camel.processor.MulticastProcessor; +import org.apache.camel.spi.AssemblerResolver; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; import org.apache.camel.spi.BeanProcessorFactory; @@ -360,6 +361,11 @@ public class SimpleCamelContext extends AbstractCamelContext { } @Override + protected AssemblerResolver createAssemblerResolver() { + return new DefaultAssemblerResolver(); + } + + @Override protected RestRegistryFactory createRestRegistryFactory() { return new BaseServiceResolver<>(RestRegistryFactory.FACTORY, RestRegistryFactory.class) .resolve(getCamelContextReference()) diff --git a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/CamelCatalogEndpointUriAssembler.java b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/CamelCatalogEndpointUriAssembler.java index 7245b8d..13aaba1 100644 --- a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/CamelCatalogEndpointUriAssembler.java +++ b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/CamelCatalogEndpointUriAssembler.java @@ -17,9 +17,16 @@ import static org.apache.camel.catalog.RuntimeCamelCatalog.ENDPOINT_URI_ASSEMBLE * Uses {@link RuntimeCamelCatalog} to assemble the endpoint uri. */ @JdkService(ENDPOINT_URI_ASSEMBLER_FACTORY) +@Deprecated public class CamelCatalogEndpointUriAssembler implements EndpointUriAssembler { @Override + public boolean isEnabled(String scheme) { + // as its a fallback then assume it can handle this + return true; + } + + @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) { try { Map<String, String> copy = new LinkedHashMap<>(); diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java index 74b77e7..1cfa827 100644 --- a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java +++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java @@ -23,6 +23,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com case "AllowUseOriginalMessage": target.setAllowUseOriginalMessage(property(camelContext, java.lang.Boolean.class, value)); return true; case "applicationcontextclassloader": case "ApplicationContextClassLoader": target.setApplicationContextClassLoader(property(camelContext, java.lang.ClassLoader.class, value)); return true; + case "assemblerresolver": + case "AssemblerResolver": target.setAssemblerResolver(property(camelContext, org.apache.camel.spi.AssemblerResolver.class, value)); return true; case "asyncprocessorawaitmanager": case "AsyncProcessorAwaitManager": target.setAsyncProcessorAwaitManager(property(camelContext, org.apache.camel.spi.AsyncProcessorAwaitManager.class, value)); return true; case "autostartup": @@ -162,6 +164,7 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com Map<String, Object> answer = new CaseInsensitiveMap(); answer.put("AllowUseOriginalMessage", java.lang.Boolean.class); answer.put("ApplicationContextClassLoader", java.lang.ClassLoader.class); + answer.put("AssemblerResolver", org.apache.camel.spi.AssemblerResolver.class); answer.put("AsyncProcessorAwaitManager", org.apache.camel.spi.AsyncProcessorAwaitManager.class); answer.put("AutoStartup", java.lang.Boolean.class); answer.put("BacklogTracing", java.lang.Boolean.class); @@ -238,6 +241,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com case "AllowUseOriginalMessage": return target.isAllowUseOriginalMessage(); case "applicationcontextclassloader": case "ApplicationContextClassLoader": return target.getApplicationContextClassLoader(); + case "assemblerresolver": + case "AssemblerResolver": return target.getAssemblerResolver(); case "asyncprocessorawaitmanager": case "AsyncProcessorAwaitManager": return target.getAsyncProcessorAwaitManager(); case "autostartup": diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java index 235fdfa..139b69b 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java @@ -71,6 +71,7 @@ import org.apache.camel.model.transformer.TransformerDefinition; import org.apache.camel.model.validator.ValidatorDefinition; import org.apache.camel.processor.channel.DefaultChannel; import org.apache.camel.spi.AnnotationBasedProcessorFactory; +import org.apache.camel.spi.AssemblerResolver; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; import org.apache.camel.spi.BeanProcessorFactory; @@ -1412,6 +1413,16 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam } @Override + public AssemblerResolver getAssemblerResolver() { + return getExtendedCamelContext().getAssemblerResolver(); + } + + @Override + public void setAssemblerResolver(AssemblerResolver assemblerResolver) { + getExtendedCamelContext().setAssemblerResolver(assemblerResolver); + } + + @Override public RouteController getInternalRouteController() { return getExtendedCamelContext().getInternalRouteController(); } diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java index 4c993ae..cbc7fc8 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java @@ -67,6 +67,7 @@ import org.apache.camel.impl.engine.DefaultDataFormatResolver; import org.apache.camel.impl.engine.DefaultLanguageResolver; import org.apache.camel.impl.engine.EndpointKey; import org.apache.camel.spi.AnnotationBasedProcessorFactory; +import org.apache.camel.spi.AssemblerResolver; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.BeanIntrospection; import org.apache.camel.spi.BeanProcessorFactory; @@ -1858,8 +1859,17 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat } @Override + public AssemblerResolver getAssemblerResolver() { + throw new UnsupportedOperationException(); + } + + @Override + public void setAssemblerResolver(AssemblerResolver assemblerResolver) { + throw new UnsupportedOperationException(); + } + + @Override public EndpointUriAssembler getEndpointUriAssembler(String scheme) { - // TODO: If this experiment is continued then this should be implemented throw new UnsupportedOperationException(); } diff --git a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriAssemblerTest.java b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriAssemblerTest.java index 30ef452..4dbdb16 100644 --- a/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriAssemblerTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/catalog/CustomEndpointUriAssemblerTest.java @@ -23,6 +23,7 @@ import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; import org.apache.camel.spi.EndpointUriAssembler; import org.apache.camel.support.component.EndpointUriAssemblerSupport; import org.junit.jupiter.api.Assertions; @@ -45,6 +46,21 @@ public class CustomEndpointUriAssemblerTest extends ContextTestSupport { } @Test + public void testCustomAssembleRegistry() throws Exception { + context.getRegistry().bind("myAssembler", new MyAssembler()); + + Map<String, Object> params = new HashMap<>(); + params.put("name", "foo"); + params.put("amount", "123"); + params.put("port", 4444); + params.put("verbose", true); + + EndpointUriAssembler assembler = context.adapt(ExtendedCamelContext.class).getEndpointUriAssembler("acme"); + String uri = assembler.buildUri(context, "acme", params); + Assertions.assertEquals("acme:foo:4444?amount=123&verbose=true", uri); + } + + @Test public void testCustomAssembleUnsorted() throws Exception { EndpointUriAssembler assembler = new MyAssembler(); @@ -71,7 +87,8 @@ public class CustomEndpointUriAssemblerTest extends ContextTestSupport { assembler.buildUri(context, "acme", params); Assertions.fail(); } catch (IllegalArgumentException e) { - Assertions.assertEquals("Option name is required when creating endpoint uri with syntax acme:name:port", e.getMessage()); + Assertions.assertEquals("Option name is required when creating endpoint uri with syntax acme:name:port", + e.getMessage()); } } @@ -149,6 +166,11 @@ public class CustomEndpointUriAssemblerTest extends ContextTestSupport { private static final String SYNTAX = "acme:name:port"; @Override + public boolean isEnabled(String scheme) { + return "acme".equals(scheme); + } + + @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { // begin from syntax @@ -170,6 +192,11 @@ public class CustomEndpointUriAssemblerTest extends ContextTestSupport { private static final String SYNTAX = "acme2:name/path:port"; @Override + public boolean isEnabled(String scheme) { + return "acme2".equals(scheme); + } + + @Override public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException { // begin from syntax diff --git a/core/camel-core/src/test/java/org/apache/camel/component/log/LogEndpointUriAssemblerTest.java b/core/camel-core/src/test/java/org/apache/camel/component/log/LogEndpointUriAssemblerTest.java new file mode 100644 index 0000000..f8115fd --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/log/LogEndpointUriAssemblerTest.java @@ -0,0 +1,31 @@ +package org.apache.camel.component.log; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.spi.EndpointUriAssembler; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LogEndpointUriAssemblerTest extends ContextTestSupport { + + @Test + public void testLogAssembler() throws Exception { + Map<String, Object> params = new HashMap<>(); + params.put("loggerName", "foo"); + params.put("groupSize", "123"); + params.put("showExchangePattern", false); + params.put("logMask", true); + + // should find the source code generated assembler via classpath + EndpointUriAssembler assembler = context.adapt(ExtendedCamelContext.class).getEndpointUriAssembler("log"); + Assertions.assertNotNull(assembler); + boolean generated = assembler instanceof LogEndpointUriAssembler; + Assertions.assertTrue(generated); + + String uri = assembler.buildUri(context, "log", params); + Assertions.assertEquals("log:foo?groupSize=123&logMask=true&showExchangePattern=false", uri); + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/AssembleResolverTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/AssembleResolverTest.java new file mode 100644 index 0000000..f4225d9 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/impl/AssembleResolverTest.java @@ -0,0 +1,43 @@ +/* + * 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.impl; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.catalog.impl.CamelCatalogEndpointUriAssembler; +import org.apache.camel.spi.EndpointUriAssembler; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AssembleResolverTest extends ContextTestSupport { + + @Test + public void testAssembleResolver() throws Exception { + // will use source code generated + EndpointUriAssembler assembler = context.adapt(ExtendedCamelContext.class).getAssemblerResolver() + .resolveAssembler("log", context); + Assertions.assertNotNull(assembler); + // TODO: check classname + + // will then use fallback that is catalog based + assembler = context.adapt(ExtendedCamelContext.class).getAssemblerResolver() + .resolveAssembler("unknown", context); + Assertions.assertNotNull(assembler); + boolean catalog = assembler instanceof CamelCatalogEndpointUriAssembler; + Assertions.assertTrue(catalog); + } +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriAssemblerSupport.java b/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriAssemblerSupport.java index d3e1c8c..9b5a6f6 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriAssemblerSupport.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/component/EndpointUriAssemblerSupport.java @@ -49,7 +49,7 @@ public abstract class EndpointUriAssemblerSupport { int pos = uri.indexOf(name); if (pos != -1) { // remove from syntax - uri = uri.replace(name, ""); + uri = uri.replaceFirst(name, ""); pos = pos - 1; // remove the separator char char ch = uri.charAt(pos); diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointUriAssemblerGenerator.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointUriAssemblerGenerator.java index 01b2e38..abba8520 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointUriAssemblerGenerator.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/EndpointUriAssemblerGenerator.java @@ -18,6 +18,7 @@ package org.apache.camel.maven.packaging; import java.io.IOException; import java.io.Writer; +import java.util.StringJoiner; import org.apache.camel.tooling.model.BaseOptionModel; import org.apache.camel.tooling.model.ComponentModel; @@ -46,14 +47,34 @@ public final class EndpointUriAssemblerGenerator { w.write(" */\n"); w.write("public class " + cn + " extends " + psn + " implements EndpointUriAssembler {\n"); w.write("\n"); - w.write(" private static final String SYNTAX = \"" + model.getSyntax() + "\";\n"); + w.write(" private static final String BASE = \"" + baseSyntax(model) + "\";\n"); + + String alternative = alternativeSchemes(model); + if (alternative != null) { + w.write(" private static final String[] SCHEMES = " + alternative + ";\n"); + } + w.write("\n"); + w.write(" @Override\n"); + w.write(" public boolean isEnabled(String scheme) {\n"); + if (alternative == null) { + w.write(" return \"" + model.getScheme() + "\".equals(scheme);\n"); + } else { + w.write(" for (String s : SCHEMES) {\n"); + w.write(" if (s.equals(scheme)) {\n"); + w.write(" return true;\n"); + w.write(" }\n"); + w.write(" }\n"); + w.write(" return false;\n"); + } + w.write(" }\n"); w.write("\n"); w.write(" @Override\n"); w.write(" public String buildUri(CamelContext camelContext, String scheme, Map<String, Object> parameters) throws URISyntaxException {\n"); - w.write(" String uri = SYNTAX;\n"); + w.write(" String syntax = scheme + BASE;\n"); + w.write(" String uri = syntax;\n"); w.write("\n"); for (BaseOptionModel option : model.getEndpointPathOptions()) { - w.write(" uri = buildPathParameter(camelContext, SYNTAX, uri, \"" + option.getName() + "\", " + w.write(" uri = buildPathParameter(camelContext, syntax, uri, \"" + option.getName() + "\", " + option.getDefaultValue() + ", " + option.isRequired() + ", parameters);\n"); } w.write(" uri = buildQueryParameters(camelContext, uri, parameters);\n"); @@ -63,4 +84,28 @@ public final class EndpointUriAssemblerGenerator { w.write("\n"); } + private static String alternativeSchemes(ComponentModel model) { + StringBuilder sb = new StringBuilder(); + if (model.getAlternativeSchemes() != null) { + sb.append("new String[]{"); + String[] alts = model.getAlternativeSchemes().split(","); + StringJoiner sj = new StringJoiner(", "); + for (String alt : alts) { + sj.add("\"" + alt + "\""); + } + sb.append(sj.toString()); + sb.append("}"); + } + if (sb.length() == 0) { + return null; + } + return sb.toString(); + } + + private static String baseSyntax(ComponentModel model) { + String base = model.getSyntax(); + base = base.replaceFirst(model.getScheme(), ""); + return base; + } + }