This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 186e8a28f5dfd43136496eebcd42b905b2f1744d Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sat Jul 6 09:56:29 2019 +0200 CAMEL-13730: Add NotifyBuilderMatcher in SPI so we can have mock endpoints back with notify builder as predicates. --- .../apache/camel/component/mock/MockEndpoint.java | 27 +++- .../org/apache/camel/spi/NotifyBuilderMatcher.java | 46 ++++++ .../org/apache/camel/builder/NotifyBuilder.java | 166 +++++++++++++++++++++ 3 files changed, 238 insertions(+), 1 deletion(-) diff --git a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java index 12e4827..3ee6959 100644 --- a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java +++ b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java @@ -43,8 +43,10 @@ import org.apache.camel.Message; import org.apache.camel.Predicate; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.RuntimeExchangeException; import org.apache.camel.spi.BrowsableEndpoint; import org.apache.camel.spi.InterceptSendToEndpoint; +import org.apache.camel.spi.NotifyBuilderMatcher; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; @@ -88,7 +90,7 @@ import org.apache.camel.util.StopWatch; * number of values provided in the bodies/headers. */ @UriEndpoint(firstVersion = "1.0.0", scheme = "mock", title = "Mock", syntax = "mock:name", producerOnly = true, label = "core,testing", lenientProperties = true) -public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint { +public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint, NotifyBuilderMatcher { // must be volatile so changes is visible between the thread which performs the assertions // and the threads which process the exchanges when routing messages in Camel @@ -1085,6 +1087,29 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint { return getReceivedExchange(index); } + @Override + public void notifyBuilderOnExchange(Exchange exchange) { + onExchange(exchange); + } + + @Override + public void notifyBuilderReset() { + reset(); + } + + @Override + public boolean notifyBuilderMatches() { + if (latch != null) { + try { + return latch.await(0, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw RuntimeExchangeException.wrapRuntimeException(e); + } + } else { + return true; + } + } + // Properties // ------------------------------------------------------------------------- diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/NotifyBuilderMatcher.java b/core/camel-api/src/main/java/org/apache/camel/spi/NotifyBuilderMatcher.java new file mode 100644 index 0000000..a951545 --- /dev/null +++ b/core/camel-api/src/main/java/org/apache/camel/spi/NotifyBuilderMatcher.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.spi; + +import org.apache.camel.Exchange; + +/** + * Allows to be used in combination with <tt>NotifyBuilder</tt> as external predicate implementations to compute + * if the exchange matches. + * <p/> + * This is used by the mock endpoint, for example. + */ +public interface NotifyBuilderMatcher { + + /** + * When an exchange was received + * + * @param exchange the exchange + */ + void notifyBuilderOnExchange(Exchange exchange); + + /** + * Whether the predicate matches + */ + boolean notifyBuilderMatches(); + + /** + * Reset state + */ + void notifyBuilderReset(); + +} diff --git a/core/camel-core/src/main/java/org/apache/camel/builder/NotifyBuilder.java b/core/camel-core/src/main/java/org/apache/camel/builder/NotifyBuilder.java index 1fba0ff..c569a79 100644 --- a/core/camel-core/src/main/java/org/apache/camel/builder/NotifyBuilder.java +++ b/core/camel-core/src/main/java/org/apache/camel/builder/NotifyBuilder.java @@ -37,6 +37,7 @@ import org.apache.camel.spi.CamelEvent.ExchangeCompletedEvent; import org.apache.camel.spi.CamelEvent.ExchangeCreatedEvent; import org.apache.camel.spi.CamelEvent.ExchangeFailedEvent; import org.apache.camel.spi.CamelEvent.ExchangeSentEvent; +import org.apache.camel.spi.NotifyBuilderMatcher; import org.apache.camel.spi.RouteContext; import org.apache.camel.spi.UnitOfWork; import org.apache.camel.support.EndpointHelper; @@ -975,6 +976,171 @@ public class NotifyBuilder { } /** + * Sets a condition when the provided mock is satisfied based on {@link Exchange} + * being sent to it when they are <b>done</b>. + * <p/> + * The idea is that you can use mock endpoints (or other matchers) for setting fine grained expectations + * and then use that together with this builder. The mock provided does <b>NOT</b> + * have to already exist in the route. You can just create a new pseudo mock + * and this builder will send the done {@link Exchange} to it. So its like + * adding the mock to the end of your route(s). + * + * @param matcher the matcher such as mock endpoint + * @return the builder + */ + public NotifyBuilder whenDoneSatisfied(final NotifyBuilderMatcher matcher) { + return doWhenSatisfied(matcher, false); + } + + /** + * Sets a condition when the provided mock endpoint (or other matchers) is satisfied based on {@link Exchange} + * being sent to it when they are <b>received</b>. + * <p/> + * The idea is that you can use mock endpoints (or other matchers) for setting fine grained expectations + * and then use that together with this builder. The mock provided does <b>NOT</b> + * have to already exist in the route. You can just create a new pseudo mock + * and this builder will send the done {@link Exchange} to it. So its like + * adding the mock to the end of your route(s). + * + * @param matcher the matcher such as mock endpoint + * @return the builder + */ + public NotifyBuilder whenReceivedSatisfied(final NotifyBuilderMatcher matcher) { + return doWhenSatisfied(matcher, true); + } + + private NotifyBuilder doWhenSatisfied(final NotifyBuilderMatcher matcher, final boolean received) { + stack.add(new EventPredicateSupport() { + + @Override + public boolean onExchangeCreated(Exchange exchange) { + if (received) { + matcher.notifyBuilderOnExchange(exchange); + } + return true; + } + + @Override + public boolean onExchangeFailed(Exchange exchange) { + if (!received) { + matcher.notifyBuilderOnExchange(exchange); + } + return true; + } + + @Override + public boolean onExchangeCompleted(Exchange exchange) { + if (!received) { + matcher.notifyBuilderOnExchange(exchange); + } + return true; + } + + public boolean matches() { + return matcher.notifyBuilderMatches(); + } + + @Override + public void reset() { + matcher.notifyBuilderReset(); + } + + @Override + public String toString() { + if (received) { + return "whenReceivedSatisfied(" + matcher + ")"; + } else { + return "whenDoneSatisfied(" + matcher + ")"; + } + } + }); + return this; + } + + /** + * Sets a condition when the provided mock (or other matchers) is <b>not</b> satisfied based on {@link Exchange} + * being sent to it when they are <b>received</b>. + * <p/> + * The idea is that you can use mock endpoints (or other matchers) for setting fine grained expectations + * and then use that together with this builder. The mock provided does <b>NOT</b> + * have to already exist in the route. You can just create a new pseudo mock + * and this builder will send the done {@link Exchange} to it. So its like + * adding the mock to the end of your route(s). + * + * @param matcher the matcher such as mock endpoint + * @return the builder + */ + @Deprecated + public NotifyBuilder whenReceivedNotSatisfied(final NotifyBuilderMatcher matcher) { + return doWhenNotSatisfied(matcher, true); + } + + /** + * Sets a condition when the provided mock (or other matchers) is <b>not</b> satisfied based on {@link Exchange} + * being sent to it when they are <b>done</b>. + * <p/> + * The idea is that you can use mock endpoints (or other matchers) for setting fine grained expectations + * and then use that together with this builder. The mock provided does <b>NOT</b> + * have to already exist in the route. You can just create a new pseudo mock + * and this builder will send the done {@link Exchange} to it. So its like + * adding the mock to the end of your route(s). + * + * @param matcher the matcher such as mock endpoint + * @return the builder + */ + public NotifyBuilder whenDoneNotSatisfied(final NotifyBuilderMatcher matcher) { + return doWhenNotSatisfied(matcher, false); + } + + private NotifyBuilder doWhenNotSatisfied(final NotifyBuilderMatcher mock, final boolean received) { + stack.add(new EventPredicateSupport() { + + @Override + public boolean onExchangeCreated(Exchange exchange) { + if (received) { + mock.notifyBuilderOnExchange(exchange); + } + return true; + } + + @Override + public boolean onExchangeFailed(Exchange exchange) { + if (!received) { + mock.notifyBuilderOnExchange(exchange); + } + return true; + } + + @Override + public boolean onExchangeCompleted(Exchange exchange) { + if (!received) { + mock.notifyBuilderOnExchange(exchange); + } + return true; + } + + public boolean matches() { + return !mock.notifyBuilderMatches(); + } + + @Override + public void reset() { + mock.notifyBuilderReset(); + } + + @Override + public String toString() { + if (received) { + return "whenReceivedNotSatisfied(" + mock + ")"; + } else { + return "whenDoneNotSatisfied(" + mock + ")"; + } + } + }); + return this; + } + + /** * Prepares to append an additional expression using the <i>and</i> operator. * * @return the builder