This is an automated email from the ASF dual-hosted git repository. orpiske pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 2b695defc151dff11cac5d6e4f0302ff94beece6 Author: luke.me <[email protected]> AuthorDate: Thu Jun 15 16:04:58 2023 +0900 [CAMEL-19456] The invocation of the removeRoute() method is too slow when using RAW(). --- .../camel/impl/engine/AbstractCamelContext.java | 44 +++++++++-------- .../camel/impl/engine/DefaultCamelContextTest.java | 34 +++++++++++++ .../java/org/apache/camel/impl/engine/MyBean.java | 8 ++++ .../camel/util/UnsafeUriCharactersDecoder.java | 55 ++++++++++++++++++++++ 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java index c67cadb0387..5982d6001d6 100644 --- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java +++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java @@ -175,12 +175,7 @@ import org.apache.camel.support.jsse.SSLContextParameters; import org.apache.camel.support.service.BaseService; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.support.startup.DefaultStartupStepRecorder; -import org.apache.camel.util.IOHelper; -import org.apache.camel.util.ObjectHelper; -import org.apache.camel.util.StopWatch; -import org.apache.camel.util.StringHelper; -import org.apache.camel.util.TimeUtils; -import org.apache.camel.util.URISupport; +import org.apache.camel.util.*; import org.apache.camel.vault.VaultConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -702,6 +697,10 @@ public abstract class AbstractCamelContext extends BaseService removeEndpoints(endpoint.getEndpointUri()); } + public String unsafeUriCharactersDecodeWithOutPercent(String uri){ + return UnsafeUriCharactersDecoder.decode(uri); + } + @Override public Collection<Endpoint> removeEndpoints(String uri) throws Exception { Collection<Endpoint> answer = new ArrayList<>(); @@ -710,21 +709,28 @@ public abstract class AbstractCamelContext extends BaseService answer.add(oldEndpoint); stopServices(oldEndpoint); } else { - List<NormalizedUri> toRemove = new ArrayList<>(); - for (Map.Entry<NormalizedUri, Endpoint> entry : endpoints.entrySet()) { - oldEndpoint = entry.getValue(); - if (EndpointHelper.matchEndpoint(this, oldEndpoint.getEndpointUri(), uri)) { - try { - stopServices(oldEndpoint); - } catch (Exception e) { - LOG.warn("Error stopping endpoint {}. This exception will be ignored.", oldEndpoint, e); + String decodeUri = unsafeUriCharactersDecodeWithOutPercent(uri); + oldEndpoint = endpoints.remove(getEndpointKey(decodeUri)); + if(oldEndpoint != null){ + answer.add(oldEndpoint); + stopServices(oldEndpoint); + } else { + List<NormalizedUri> toRemove = new ArrayList<>(); + for (Map.Entry<NormalizedUri, Endpoint> entry : endpoints.entrySet()) { + oldEndpoint = entry.getValue(); + if (EndpointHelper.matchEndpoint(this, oldEndpoint.getEndpointUri(), uri)) { + try { + stopServices(oldEndpoint); + } catch (Exception e) { + LOG.warn("Error stopping endpoint " + oldEndpoint + ". This exception will be ignored.", e); + } + answer.add(oldEndpoint); + toRemove.add(entry.getKey()); } - answer.add(oldEndpoint); - toRemove.add(entry.getKey()); } - } - for (NormalizedUri key : toRemove) { - endpoints.remove(key); + for (NormalizedUri key : toRemove) { + endpoints.remove(key); + } } } diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java index 5e236feec55..6322df0088c 100644 --- a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java @@ -18,6 +18,7 @@ package org.apache.camel.impl.engine; import java.util.Collection; import java.util.Iterator; +import java.util.Map; import java.util.Set; import org.apache.camel.CamelContext; @@ -37,6 +38,7 @@ import org.apache.camel.spi.EndpointRegistry; import org.apache.camel.spi.UuidGenerator; import org.apache.camel.support.CamelContextHelper; import org.apache.camel.support.DefaultUuidGenerator; +import org.apache.camel.support.NormalizedUri; import org.apache.camel.support.service.ServiceSupport; import org.junit.jupiter.api.Test; @@ -413,6 +415,38 @@ public class DefaultCamelContextTest extends TestSupport { assertNull(ctx.hasService(MyService.class)); } + @Test + public void testRemoveRoute() throws Exception { + DefaultCamelContext ctx = new DefaultCamelContext(false); + + ctx.disableJMX(); + ctx.getRegistry().bind("MyBean", MyBean.class); + + ctx.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId("rawRoute").to("bean:MyBean?method=RAW(addString('aa a',${body}))"); + } + }); + ctx.start(); + + + EndpointRegistry<NormalizedUri> endpoints = ctx.getEndpointRegistry(); + Map<String, RouteService> routeServices = ctx.getRouteServices(); + Set<Endpoint> routeEndpoints = routeServices.get("rawRoute").gatherEndpoints(); + for(Endpoint endpoint : routeEndpoints) { + Endpoint oldEndpoint = endpoints.remove(ctx.getEndpointKey(endpoint.getEndpointUri())); + if(oldEndpoint == null){ + oldEndpoint = endpoints.remove(ctx.getEndpointKey(ctx.unsafeUriCharactersDecodeWithOutPercent(endpoint.getEndpointUri()))); + }else { + assertNotNull(oldEndpoint); + } + assertNotNull(oldEndpoint); + } + + } + + private static class MyService extends ServiceSupport implements CamelContextAware { private CamelContext camelContext; diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/MyBean.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/MyBean.java new file mode 100644 index 00000000000..d6e9faf43e2 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/MyBean.java @@ -0,0 +1,8 @@ +package org.apache.camel.impl.engine; + [email protected](value = "MyBean") +public class MyBean { + public String addString(String source, String dst) throws Exception { + return source + dst; + } +} diff --git a/core/camel-util/src/main/java/org/apache/camel/util/UnsafeUriCharactersDecoder.java b/core/camel-util/src/main/java/org/apache/camel/util/UnsafeUriCharactersDecoder.java new file mode 100644 index 00000000000..6fa7af5a49b --- /dev/null +++ b/core/camel-util/src/main/java/org/apache/camel/util/UnsafeUriCharactersDecoder.java @@ -0,0 +1,55 @@ +package org.apache.camel.util; + + +import java.util.HashMap; +import java.util.Map; + +public final class UnsafeUriCharactersDecoder { + private static final Map<String,String> unsafeStringsRfc1738; + + static { + unsafeStringsRfc1738 = new HashMap<>(); + unsafeStringsRfc1738.put("%22","\""); + unsafeStringsRfc1738.put("%3C","<"); + unsafeStringsRfc1738.put("%3E",">"); + unsafeStringsRfc1738.put("%7B","{"); + unsafeStringsRfc1738.put("%7D","}"); + unsafeStringsRfc1738.put("%7C","|"); + unsafeStringsRfc1738.put("%5C","\\\\"); + unsafeStringsRfc1738.put("%5E","^"); + unsafeStringsRfc1738.put("%7E","~"); + unsafeStringsRfc1738.put("%5B","["); + unsafeStringsRfc1738.put("%5D","]"); + unsafeStringsRfc1738.put("%60","`"); + unsafeStringsRfc1738.put("%20"," "); + unsafeStringsRfc1738.put("%23","#"); + } + + public static String decode(String uri){ + int len = uri.length(); + StringBuilder sb = new StringBuilder(len > 500 ? len / 2 : len); + for (int i = 0; i < len; i++) { + char ch = uri.charAt(i); + if (ch == '%') { + char next = i + 1 < len ? uri.charAt(i + 1) : ' '; + char next2 = i + 2 < len ? uri.charAt(i + 2) : ' '; + String encodedString = String.valueOf(ch) + next + next2; + if (isHexDigit(next) && isHexDigit(next2) && unsafeStringsRfc1738.containsKey(encodedString.toUpperCase())) { + i = i + 2; + sb.append(unsafeStringsRfc1738.get(encodedString)); + } else { + sb.append(ch); + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } + + private static boolean isHexDigit(char ch) { + // 0..9 A..F a..f + return ch >= 48 && ch <= 57 || ch >= 65 && ch <= 70 || ch >= 97 && ch <= 102; + } + +} \ No newline at end of file
