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
The following commit(s) were added to refs/heads/master by this push: new 50c67a6 CAMEL-14191: EIP docs - Add links to last EIP patterns and add new pages if missing content 50c67a6 is described below commit 50c67a6975ebe2eb311400b5f408bc314eb33624 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Nov 20 08:29:24 2019 +0100 CAMEL-14191: EIP docs - Add links to last EIP patterns and add new pages if missing content --- .../ROOT/assets/images/eip/CompetingConsumers.gif | Bin 0 -> 4759 bytes .../ROOT/assets/images/eip/MessageDispatcher.gif | Bin 0 -> 5128 bytes .../assets/images/eip/MessageSelectorSolution.gif | Bin 0 -> 2987 bytes .../images/eip/MessagingMapperClassDiagram.gif | Bin 0 -> 2019 bytes .../modules/ROOT/pages/competing-consumers.adoc | 105 +++++++++++++++++++++ .../pages/enterprise-integration-patterns.adoc | 8 +- .../modules/ROOT/pages/message-dispatcher.adoc | 15 +++ .../modules/ROOT/pages/messaging-mapper.adoc | 24 +++++ .../modules/ROOT/pages/selective-consumer.adoc | 46 +++++++++ 9 files changed, 194 insertions(+), 4 deletions(-) diff --git a/docs/user-manual/modules/ROOT/assets/images/eip/CompetingConsumers.gif b/docs/user-manual/modules/ROOT/assets/images/eip/CompetingConsumers.gif new file mode 100644 index 0000000..5d9c730 Binary files /dev/null and b/docs/user-manual/modules/ROOT/assets/images/eip/CompetingConsumers.gif differ diff --git a/docs/user-manual/modules/ROOT/assets/images/eip/MessageDispatcher.gif b/docs/user-manual/modules/ROOT/assets/images/eip/MessageDispatcher.gif new file mode 100644 index 0000000..ae27b08 Binary files /dev/null and b/docs/user-manual/modules/ROOT/assets/images/eip/MessageDispatcher.gif differ diff --git a/docs/user-manual/modules/ROOT/assets/images/eip/MessageSelectorSolution.gif b/docs/user-manual/modules/ROOT/assets/images/eip/MessageSelectorSolution.gif new file mode 100644 index 0000000..58447a3 Binary files /dev/null and b/docs/user-manual/modules/ROOT/assets/images/eip/MessageSelectorSolution.gif differ diff --git a/docs/user-manual/modules/ROOT/assets/images/eip/MessagingMapperClassDiagram.gif b/docs/user-manual/modules/ROOT/assets/images/eip/MessagingMapperClassDiagram.gif new file mode 100644 index 0000000..00e0b18 Binary files /dev/null and b/docs/user-manual/modules/ROOT/assets/images/eip/MessagingMapperClassDiagram.gif differ diff --git a/docs/user-manual/modules/ROOT/pages/competing-consumers.adoc b/docs/user-manual/modules/ROOT/pages/competing-consumers.adoc new file mode 100644 index 0000000..845b39e --- /dev/null +++ b/docs/user-manual/modules/ROOT/pages/competing-consumers.adoc @@ -0,0 +1,105 @@ +[[Competing-Consumers]] += Competing Consumers + +Camel supports the +https://www.enterpriseintegrationpatterns.com/patterns/messaging/CompetingConsumers.html[Competing Consumers] +from the xref:enterprise-integration-patterns.adoc[EIP patterns] book. + +Camel supports the Competing Consumers from the EIP patterns directly from components that can do this. +For example from SEDA, JMS, Kafka, and various AWS components. + +image::eip/CompetingConsumers.gif[image] + +- SEDA for SEDA based concurrent processing using a thread pool +- JMS for distributed SEDA based concurrent processing with queues which support reliable load balancing, failover and clustering. + +For components which does not allow concurrent consumers, then Camel allows to route from the consumer +to a thread-pool which can then further process the message concurrently, +which then simulates a _quasi like_ competing consumers. + +== Competing Consumers with JMS + +To enable Competing Consumers you just need to set the `concurrentConsumers` property on the JMS endpoint. + +For example + +[source,java] +---- +from("jms:MyQueue?concurrentConsumers=5") + .to("bean:someBean"); +---- + +or in XML DSL + +[source,xml] +---- +<route> + <from uri="jms:MyQueue?concurrentConsumers=5"/> + <to uri="bean:someBean"/> +</route> +---- + +== Competing Consumers with Thread Pool + +You can simulate competing consumers by using a thread pool which then continue processing the messages concurrently. +Then the single thread consumer can quickly continue and pickup new messages to process and offload them to the thread-pool +(and its task queue). + +Suppose we have this simple route where we poll a folder for new files, +process the files and afterwards move the files to a backup folder when complete. + +[source,java] +---- +from("file://inbox?move=../backup-${date:now:yyyyMMdd}") + .to("bean:calculateBean"); +---- + +The route is synchronous and there is only a single consumer running at any given time. +This scenario is well known and it doesn't affect thread safety as we only have one active thread +involved at any given time. + +Now imagine that the inbox folder is filled with filers quicker than we can process. +So we want to speed up this process. How can we do this? + +Well we could try adding a 2nd route with the same route path. +Well that doesn't work so well as we have competing consumers for the same files. +That requires however that we use file locking so we wont have two consumers compete for the same file. +By default Camel support this with its file locking option on the file component. + +But what if the component doesn't support this, or its not possible to add a 2nd consumer +for the same endpoint? And yes its a bit of a hack and the route logic code is duplicated. +And what if we need more, then we need to add a 3rd, a 4th and so on. + +What if the processing of the file itself is the bottleneck? That is the calculateBean is slow. +So how can we process messages with this bean concurrently? + +Yeah we can use the xref:threads-eip.adoc[Threads EIP], so if we insert it in the route we get: + +[source,java] +---- +from("file://inbox?move=../backup-${date:now:yyyyMMdd}") + .threads(10) + .to("bean:calculateBean"); +---- + +So by inserting `threads(10)` we have instructed Camel that from this point forward in the route +it should use a thread pool with up till 10 concurrent threads. +So when the file consumer delivers a message to the threads, then the threads take it from there +and the file consumer can return and continue to poll the next file. + +By leveraging this fact we can still use a single file consumer to poll new files. +And polling a directory to just grab the file handle is very fast. +And we wont have problem with file locking, sorting, filtering and whatnot. +And at the same time we can leverage the fact that we can process the file messages concurrently +by the calculate bean. + +Here at the end lets take a closer look what happens with the synchronous thread and the +asynchronous thread. The synchronous thread hands over the exchange to the new asynchronous thread and as +such the synchronous thread completes. The asynchronous thread is then routing and processing the message. +And when this thread finishes it will take care of the file completion strategy to move the file +into the backup folder. This is an important note, that the on completion is done by the asynchronous thread. + +This ensures the file is not moved before the file is processed successfully. Suppose the calculate bean +could not process one of the files. If it was the asynchronous thread that should do the on completion strategy +then the file would have been moved to early into the backup folder. By handing over this to the asynchronous +thread we do it after we have processed the message completely diff --git a/docs/user-manual/modules/ROOT/pages/enterprise-integration-patterns.adoc b/docs/user-manual/modules/ROOT/pages/enterprise-integration-patterns.adoc index 776988d..5b897da 100644 --- a/docs/user-manual/modules/ROOT/pages/enterprise-integration-patterns.adoc +++ b/docs/user-manual/modules/ROOT/pages/enterprise-integration-patterns.adoc @@ -220,7 +220,7 @@ semantically equivalent, but arrive in a different format? [width="100%",cols="10%,10%,80%",] |======================================================================= | -|Messaging Mapper |How do you move data +|xref:messaging-mapper.adoc[Messaging Mapper] |How do you move data between domain objects and the messaging infrastructure while keeping the two independent of each other? @@ -233,15 +233,15 @@ a|image::eip/PollingConsumerIcon.gif[image] consume a message when the application is ready? a|image::eip/CompetingConsumersIcon.gif[image] -|Competing Consumers |How can a messaging +|xref:competing-consumers.adoc[Competing Consumers] |How can a messaging client process multiple messages concurrently? a|image::eip/MessageDispatcherIcon.gif[image] -|Message Dispatcher |How can multiple +|xref:message-dispatcher.adoc[Message Dispatcher] |How can multiple consumers on a single channel coordinate their message processing? a|image::eip/MessageSelectorIcon.gif[image] -|Selective Consumer |How can a message +|xref:selective-consumer.adoc[Selective Consumer] |How can a message consumer select which messages it wishes to receive? a|image::eip/DurableSubscriptionIcon.gif[image] diff --git a/docs/user-manual/modules/ROOT/pages/message-dispatcher.adoc b/docs/user-manual/modules/ROOT/pages/message-dispatcher.adoc new file mode 100644 index 0000000..c858e0a --- /dev/null +++ b/docs/user-manual/modules/ROOT/pages/message-dispatcher.adoc @@ -0,0 +1,15 @@ +[[Message-Dispatcher]] += Message Dispatcher + +Camel supports the +https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageDispatcher.html[Message Dispatcher] +from the xref:enterprise-integration-patterns.adoc[EIP patterns] book. + +Camel supports the Message Dispatcher from the EIP patterns using various approaches. + +image::eip/MessageDispatcher.gif[image] + +You can use a component like JMS with selectors to implement a xref:selective-consumer.adoc[Selective Consumer] +as the Message Dispatcher implementation. Or you can use an xref:message-endpoint.adoc[Message Endpoint] +as the Message Dispatcher itself and then use a xref:content-based-router-eip.adoc[Content Based Router] +as the Message Dispatcher. diff --git a/docs/user-manual/modules/ROOT/pages/messaging-mapper.adoc b/docs/user-manual/modules/ROOT/pages/messaging-mapper.adoc new file mode 100644 index 0000000..ec53021 --- /dev/null +++ b/docs/user-manual/modules/ROOT/pages/messaging-mapper.adoc @@ -0,0 +1,24 @@ +[[Messaging-Mapper]] += Messaging Mapper + +Camel supports the +https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessagingMapper.html[Messaging Mapper] +from the xref:enterprise-integration-patterns.adoc[EIP patterns] book. + +How do you move data between domain objects and the messaging infrastructure while keeping the two independent of each other? + +image::eip/MessagingMapperClassDiagram.gif[image] + +Create a separate Messaging Mapper that contains the mapping logic between the messaging infrastructure and the domain objects. +Neither the objects nor the infrastructure have knowledge of the Messaging Mapper's existence. + +The Messaging Mapper accesses one or more domain objects and converts them into a message as required by the messaging channel. +It also performs the opposite function, creating or updating domain objects based on incoming messages. +Since the Messaging Mapper is implemented as a separate class that references the domain object(s) +and the messaging layer, neither layer is aware of the other. The layers don't even know about the Messaging Mapper. + +With Camel this pattern is often implemented directly via Camel components that provides +xref:type-converter[Type Converter]'s from the messaging infrastructure to common Java types or +Java Objects representing the data model of the component in question. Combining this with the +xref:message-translator.adoc[Message Translator] to have the Messaging Mapper EIP pattern. + diff --git a/docs/user-manual/modules/ROOT/pages/selective-consumer.adoc b/docs/user-manual/modules/ROOT/pages/selective-consumer.adoc new file mode 100644 index 0000000..a1f8c5f --- /dev/null +++ b/docs/user-manual/modules/ROOT/pages/selective-consumer.adoc @@ -0,0 +1,46 @@ +[[Selective-Consumer]] += Selective Consumer + +Camel supports the +https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageSelector.html[Selective Consumer] +from the xref:enterprise-integration-patterns.adoc[EIP patterns] book. + +The Selective Consumer from the EIP patterns can be implemented in two ways + +image::eip/MessageSelectorSolution.gif[image] + +== Selective Consumer using Components + +The first solution is to provide a Message Selector to the underlying URIs when creating your consumer. +For example when using JMS you can specify a selector parameter so that the message broker will only deliver messages matching your criteria. + +[source,java] +---- +from("activemq:queue:hello?selector=color='red'") + .to("bean:red"); +---- + +== Selective Consumer using Filter pattern + +The other approach is to use a xref:filter-eip.adoc[Message Filter] which is applied; +then if the filter matches the message your consumer is invoked as shown in the following example. + +[source,java] +---- +from("seda:a") + .filter(header("foo").isEqualTo("bar")) + .process(myProcessor); +---- + +And in XML + +[source,xml] +---- +<route> + <from uri="seda:a"/> + <filter> + <simple>${header.foo} == 'bar'</xpath> + <process ref="myProcessor"/> + </filter> +</route> +---- \ No newline at end of file