From b4698d7523e982438003d82bc6cd8835f8fdfaa7 Mon Sep 17 00:00:00 2001 From: ticktock Date: Wed, 25 May 2011 14:52:27 -0700 Subject: [PATCH] adding modules docs --- akka-docs/modules/camel-async-interact.png | Bin 0 -> 21857 bytes akka-docs/modules/camel-async-sequence.png | Bin 0 -> 7492 bytes akka-docs/modules/camel-custom-route.png | Bin 0 -> 21359 bytes akka-docs/modules/camel-pubsub.png | Bin 0 -> 18824 bytes akka-docs/modules/camel-pubsub2.png | Bin 0 -> 10529 bytes akka-docs/modules/camel.rst | 2915 ++++++++++++++++++++ akka-docs/modules/microkernel.rst | 53 + akka-docs/modules/spring.rst | 335 +++ 8 files changed, 3303 insertions(+) create mode 100644 akka-docs/modules/camel-async-interact.png create mode 100644 akka-docs/modules/camel-async-sequence.png create mode 100644 akka-docs/modules/camel-custom-route.png create mode 100644 akka-docs/modules/camel-pubsub.png create mode 100644 akka-docs/modules/camel-pubsub2.png create mode 100644 akka-docs/modules/camel.rst create mode 100644 akka-docs/modules/microkernel.rst create mode 100644 akka-docs/modules/spring.rst diff --git a/akka-docs/modules/camel-async-interact.png b/akka-docs/modules/camel-async-interact.png new file mode 100644 index 0000000000000000000000000000000000000000..55a2a4505b1f618641b1ec2b7ca78b9615aaa6c9 GIT binary patch literal 21857 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 literal 0 HcmV?d00001 diff --git a/akka-docs/modules/camel-async-sequence.png b/akka-docs/modules/camel-async-sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..416c5a181b6ab63a43f18b28fe6dd1f5eaf13e65 GIT binary patch literal 7492 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 I>zopr0KaKuX8-^I literal 0 HcmV?d00001 diff --git a/akka-docs/modules/camel-custom-route.png b/akka-docs/modules/camel-custom-route.png new file mode 100644 index 0000000000000000000000000000000000000000..efacdb8f8296678cdd3465985090a1fd9419f19a GIT binary patch literal 21359 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 literal 0 HcmV?d00001 diff --git a/akka-docs/modules/camel-pubsub2.png b/akka-docs/modules/camel-pubsub2.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3b93568d5aa72914fc88d5d2a705b2a372ff17 GIT binary patch literal 10529 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 literal 0 HcmV?d00001 diff --git a/akka-docs/modules/camel.rst b/akka-docs/modules/camel.rst new file mode 100644 index 0000000000..08a7dee6e7 --- /dev/null +++ b/akka-docs/modules/camel.rst @@ -0,0 +1,2915 @@ + +.. _camel-module: + +####### + Camel +####### + +For an introduction to akka-camel, see also the `Appendix E - Akka and Camel`_ +(pdf) of the book `Camel in Action`_. + +.. _Appendix E - Akka and Camel: http://www.manning.com/ibsen/appEsample.pdf +.. _Camel in Action: http://www.manning.com/ibsen/ + +Contents: + +.. contents:: :local: + +Other, more advanced external articles are: + +* `Akka Consumer Actors: New Features and Best Practices `_ +* `Akka Producer Actors: New Features and Best Practices `_ + + +Introduction +============ + +The akka-camel module allows actors, untyped actors, and typed actors to receive +and send messages over a great variety of protocols and APIs. This section gives +a brief overview of the general ideas behind the akka-camel module, the +remaining sections go into the details. In addition to the native Scala and Java +actor API, actors can now exchange messages with other systems over large number +of protocols and APIs such as HTTP, SOAP, TCP, FTP, SMTP or JMS, to mention a +few. At the moment, approximately 80 protocols and APIs are supported. + +The akka-camel module is based on `Apache Camel`_, a powerful and leight-weight +integration framework for the JVM. For an introduction to Apache Camel you may +want to read this `Apache Camel article`_. Camel comes with a +large number of `components`_ that provide bindings to different protocols and +APIs. The `camel-extra`_ project provides further components. + +.. _Apache Camel: http://camel.apache.org/ +.. _Apache Camel article: http://architects.dzone.com/articles/apache-camel-integration +.. _components: http://camel.apache.org/components.html +.. _camel-extra: http://code.google.com/p/camel-extra/ + +Usage of Camel's integration components in Akka is essentially a +one-liner. Here's an example. + +.. code-block:: scala + + import akka.actor.Actor + import akka.actor.Actor._ + import akka.camel.{Message, Consumer} + + class MyActor extends Actor with Consumer { + def endpointUri = "mina:tcp://localhost:6200?textline=true" + + def receive = { + case msg: Message => { /* ... */} + case _ => { /* ... */} + } + } + + // start and expose actor via tcp + val myActor = actorOf[MyActor].start + +The above example exposes an actor over a tcp endpoint on port 6200 via Apache +Camel's `Mina component`_. The actor implements the endpointUri method to define +an endpoint from which it can receive messages. After starting the actor, tcp +clients can immediately send messages to and receive responses from that +actor. If the message exchange should go over HTTP (via Camel's `Jetty +component`_), only the actor's endpointUri method must be changed. + +.. _Mina component: http://camel.apache.org/mina.html +.. _Jetty component: http://camel.apache.org/jetty.html + +.. code-block:: scala + + class MyActor extends Actor with Consumer { + def endpointUri = "jetty:http://localhost:8877/example" + + def receive = { + case msg: Message => { /* ... */} + case _ => { /* ... */} + } + } + +Actors can also trigger message exchanges with external systems i.e. produce to +Camel endpoints. + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.{Producer, Oneway} + + class MyActor extends Actor with Producer with Oneway { + def endpointUri = "jms:queue:example" + } + +In the above example, any message sent to this actor will be added (produced) to +the example JMS queue. Producer actors may choose from the same set of Camel +components as Consumer actors do. + +The number of Camel components is constantly increasing. The akka-camel module +can support these in a plug-and-play manner. Just add them to your application's +classpath, define a component-specific endpoint URI and use it to exchange +messages over the component-specific protocols or APIs. This is possible because +Camel components bind protocol-specific message formats to a Camel-specific +`normalized message format`__. The normalized message format hides +protocol-specific details from Akka and makes it therefore very easy to support +a large number of protocols through a uniform Camel component interface. The +akka-camel module further converts mutable Camel messages into `immutable +representations`__ which are used by Consumer and Producer actors for pattern +matching, transformation, serialization or storage, for example. + +__ https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/main/java/org/apache/camel/Message.java +__ http://github.com/jboner/akka-modules/blob/v0.8/akka-camel/src/main/scala/akka/Message.scala#L17 + + +Dependencies +============ + +Akka's Camel Integration consists of two modules + +* akka-camel - this module depends on akka-actor and camel-core (+ transitive + dependencies) and implements the Camel integration for (untyped) actors + +* akka-camel-typed - this module depends on akka-typed-actor and akka-camel (+ + transitive dependencies) and implements the Camel integration for typed actors + +The akka-camel-typed module is optional. To have both untyped and typed actors +working with Camel, add the following dependencies to your SBT project +definition. + +.. code-block:: scala + + import sbt._ + + class Project(info: ProjectInfo) extends DefaultProject(info) with AkkaProject { + // ... + val akkaCamel = akkaModule("camel") + val akkaCamelTyped = akkaModule("camel-typed") // optional typed actor support + // ... + } + + +.. _camel-consume-messages: + +Consume messages +================ + +Actors (untyped) +---------------- + +For actors (Scala) to receive messages, they must mixin the `Consumer`_ +trait. For example, the following actor class (Consumer1) implements the +endpointUri method, which is declared in the Consumer trait, in order to receive +messages from the ``file:data/input/actor`` Camel endpoint. Untyped actors +(Java) need to extend the abstract UntypedConsumerActor class and implement the +getEndpointUri() and onReceive(Object) methods. + +.. _Consumer: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/Consumer.scala + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.{Message, Consumer} + + class Consumer1 extends Actor with Consumer { + def endpointUri = "file:data/input/actor" + + def receive = { + case msg: Message => println("received %s" format msg.bodyAs[String]) + } + } + +**Java** + +.. code-block:: java + + import akka.camel.Message; + import akka.camel.UntypedConsumerActor; + + public class Consumer1 extends UntypedConsumerActor { + public String getEndpointUri() { + return "file:data/input/actor"; + } + + public void onReceive(Object message) { + Message msg = (Message)message; + String body = msg.getBodyAs(String.class); + System.out.println(String.format("received %s", body)) + } + } + +Whenever a file is put into the data/input/actor directory, its content is +picked up by the Camel `file component`_ and sent as message to the +actor. Messages consumed by actors from Camel endpoints are of type +`Message`_. These are immutable representations of Camel messages. + +.. _file component: http://camel.apache.org/file2.html +.. _Message: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/Message.scala + +For Message usage examples refer to the unit tests: + +* Message unit tests - `Scala API `_ +* Message unit tests - `Java API `_ + +Here's another example that sets the endpointUri to +``jetty:http://localhost:8877/camel/default``. It causes Camel's `Jetty +component`_ to start an embedded `Jetty`_ server, accepting HTTP connections +from localhost on port 8877. + +.. _Jetty component: http://camel.apache.org/jetty.html +.. _Jetty: http://www.eclipse.org/jetty/ + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.{Message, Consumer} + + class Consumer2 extends Actor with Consumer { + def endpointUri = "jetty:http://localhost:8877/camel/default" + + def receive = { + case msg: Message => self.reply("Hello %s" format msg.bodyAs[String]) + } + } + +**Java** + +.. code-block:: java + + import akka.camel.Message; + import akka.camel.UntypedConsumerActor; + + public class Consumer2 extends UntypedConsumerActor { + public String getEndpointUri() { + return "jetty:http://localhost:8877/camel/default"; + } + + public void onReceive(Object message) { + Message msg = (Message)message; + String body = msg.getBodyAs(String.class); + getContext().replySafe(String.format("Hello %s", body)); + } + } + +After starting the actor, clients can send messages to that actor by POSTing to +``http://localhost:8877/camel/default``. The actor sends a response by using the +self.reply method (Scala). For returning a message body and headers to the HTTP +client the response type should be `Message`_. For any other response type, a +new Message object is created by akka-camel with the actor response as message +body. + +.. _Message: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/Message.scala + + +Typed actors +------------ + +Typed actors can also receive messages from Camel endpoints. In contrast to +(untyped) actors, which only implement a single receive or onReceive method, a +typed actor may define several (message processing) methods, each of which can +receive messages from a different Camel endpoint. For a typed actor method to be +exposed as Camel endpoint it must be annotated with the `@consume +annotation`_. For example, the following typed consumer actor defines two +methods, foo and bar. + +.. _@consume annotation: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/java/akka/camel/consume.java + +**Scala** + +.. code-block:: scala + + import org.apache.camel.{Body, Header} + import akka.actor.TypedActor + import akka.camel.consume + + trait TypedConsumer1 { + @consume("file:data/input/foo") + def foo(body: String): Unit + + @consume("jetty:http://localhost:8877/camel/bar") + def bar(@Body body: String, @Header("X-Whatever") header: String): String + } + + class TypedConsumer1Impl extends TypedActor with TypedConsumer1 { + def foo(body: String) = println("Received message: %s" format body) + def bar(body: String, header: String) = "body=%s header=%s" format (body, header) + } + +**Java** + +.. code-block:: java + + import org.apache.camel.Body; + import org.apache.camel.Header; + import akka.actor.TypedActor; + import akka.camel.consume; + + public interface TypedConsumer1 { + @consume("file:data/input/foo") + public void foo(String body); + + @consume("jetty:http://localhost:8877/camel/bar") + public String bar(@Body String body, @Header("X-Whatever") String header); + } + + public class TypedConsumer1Impl extends TypedActor implements TypedConsumer1 { + public void foo(String body) { + System.out.println(String.format("Received message: ", body)); + } + + public String bar(String body, String header) { + return String.format("body=%s header=%s", body, header); + } + } + +The foo method can be invoked by placing a file in the data/input/foo +directory. Camel picks up the file from this directory and akka-camel invokes +foo with the file content as argument (converted to a String). Camel +automatically tries to convert messages to appropriate types as defined by the +method parameter(s). The conversion rules are described in detail on the +following pages: + +* `Bean integration `_ +* `Bean binding `_ +* `Parameter binding `_ + +The bar method can be invoked by POSTing a message to +http://localhost:8877/camel/bar. Here, parameter binding annotations are used to +tell Camel how to extract data from the HTTP message. The @Body annotation binds +the HTTP request body to the first parameter, the @Header annotation binds the +X-Whatever header to the second parameter. The return value is sent as HTTP +response message body to the client. + +Parameter binding annotations must be placed on the interface, the @consume +annotation can also be placed on the methods in the implementation class. + + +.. _camel-publishing: + +Consumer publishing +------------------- + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +Publishing a consumer actor at its Camel endpoint occurs when the actor is +started. Publication is done asynchronously; setting up an endpoint (more +precisely, the route from that endpoint to the actor) may still be in progress +after the ActorRef.start method returned. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor._ + + val actor = actorOf[Consumer1] // create Consumer actor + actor.start // activate endpoint in background + +**Java** + +.. code-block:: java + + import static akka.actor.Actors.*; + import akka.actor.ActorRef; + + ActorRef actor = actorOf(Consumer1.class); // create Consumer actor + actor.start(); // activate endpoint in background + + +Typed actors +^^^^^^^^^^^^ + +Publishing of typed actor methods is done when the typed actor is created with +one of the TypedActor.newInstance(..) methods. Publication is done in the +background here as well i.e. it may still be in progress when +TypedActor.newInstance(..) returns. + +**Scala** + +.. code-block:: scala + + import akka.actor.TypedActor + + // create TypedConsumer1 object and activate endpoint(s) in background + val consumer = TypedActor.newInstance(classOf[TypedConsumer1], classOf[TypedConumer1Impl]) + +**Java** + +.. code-block:: java + + import akka.actor.TypedActor; + + // create TypedConsumer1 object and activate endpoint(s) in background + TypedConsumer1 consumer = TypedActor.newInstance(TypedConsumer1.class, TypedConumer1Impl.class); + + +.. _camel-consumers-and-camel-service: + +Consumers and the CamelService +------------------------------ + +Publishing of consumer actors or typed actor methods requires a running +CamelService. The Akka :ref:`microkernel` can start a CamelService automatically +(see :ref:`camel-configuration`). When using Akka in other environments, a +CamelService must be started manually. Applications can do that by calling the +CamelServiceManager.startCamelService method. + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + + startCamelService + +**Java** + +.. code-block:: java + + import static akka.camel.CamelServiceManager.*; + + startCamelService(); + +If applications need to wait for a certain number of consumer actors or typed +actor methods to be published they can do so with the +``CamelServiceManager.mandatoryService.awaitEndpointActivation`` method, where +``CamelServiceManager.mandatoryService`` is the current CamelService instance +(or throws an IllegalStateException there's no current CamelService). + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + + startCamelService + + // Wait for three conumer endpoints to be activated + mandatoryService.awaitEndpointActivation(3) { + // Start three consumer actors (for example) + // ... + } + + // Communicate with consumer actors via their activated endpoints + // ... + +**Java** + +.. code-block:: java + + import akka.japi.SideEffect; + import static akka.camel.CamelServiceManager.*; + + startCamelService(); + + // Wait for three conumer endpoints to be activated + getMandatoryService().awaitEndpointActivation(3, new SideEffect() { + public void apply() { + // Start three consumer actors (for example) + // ... + } + }); + + // Communicate with consumer actors via their activated endpoints + // ... + +Alternatively, one can also use ``Option[CamelService]`` returned by +``CamelServiceManager.service``. + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + + startCamelService + + for(s <- service) s.awaitEndpointActivation(3) { + // ... + } + +**Java** + +.. code-block:: java + + import java.util.concurrent.CountDownLatch; + + import akka.camel.CamelService; + import static akka.camel.CamelServiceManager.*; + + startCamelService(); + + for (CamelService s : getService()) s.awaitEndpointActivation(3, new SideEffect() { + public void apply() { + // ... + } + }); + +:ref:`camel-configuration` additionally describes how a CamelContext, that is +managed by a CamelService, can be cutomized before starting the service. When +the CamelService is no longer needed, it should be stopped. + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + + stopCamelService + +**Java** + +.. code-block:: java + + import static akka.camel.CamelServiceManager.*; + + stopCamelService(); + + +.. _camel-unpublishing: + +Consumer un-publishing +---------------------- + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +When an actor is stopped, the route from the endpoint to that actor is stopped +as well. For example, stopping an actor that has been previously published at +``http://localhost:8877/camel/test`` will cause a connection failure when trying +to access that endpoint. Stopping the route is done asynchronously; it may be +still in progress after the ``ActorRef.stop`` method returned. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor._ + + val actor = actorOf[Consumer1] // create Consumer actor + actor.start // activate endpoint in background + // ... + actor.stop // deactivate endpoint in background + +**Java** + +.. code-block:: java + + import static akka.actor.Actors.*; + import akka.actor.ActorRef; + + ActorRef actor = actorOf(Consumer1.class); // create Consumer actor + actor.start(); // activate endpoint in background + // ... + actor.stop(); // deactivate endpoint in background + + +Typed actors +^^^^^^^^^^^^ + +When a typed actor is stopped, routes to @consume annotated methods of this +typed actors are stopped as well. Stopping the routes is done asynchronously; it +may be still in progress after the TypedActor.stop method returned. + +**Scala** + +.. code-block:: scala + + import akka.actor.TypedActor + + // create TypedConsumer1 object and activate endpoint(s) in background + val consumer = TypedActor.newInstance(classOf[TypedConsumer1], classOf[TypedConumer1Impl]) + + // deactivate endpoints in background + TypedActor.stop(consumer) + +**Java** + +.. code-block:: java + + import akka.actor.TypedActor; + + // Create typed consumer actor and activate endpoints in background + TypedConsumer1 consumer = TypedActor.newInstance(TypedConsumer1.class, TypedConumer1Impl.class); + + // Deactivate endpoints in background + TypedActor.stop(consumer); + + +.. _camel-acknowledgements: + +Acknowledgements +---------------- + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +With in-out message exchanges, clients usually know that a message exchange is +done when they receive a reply from a consumer actor. The reply message can be a +Message (or any object which is then internally converted to a Message) on +success, and a Failure message on failure. + +With in-only message exchanges, by default, an exchange is done when a message +is added to the consumer actor's mailbox. Any failure or exception that occurs +during processing of that message by the consumer actor cannot be reported back +to the endpoint in this case. To allow consumer actors to positively or +negatively acknowledge the receipt of a message from an in-only message +exchange, they need to override the ``autoack`` (Scala) or ``isAutoack`` (Java) +method to return false. In this case, consumer actors must reply either with a +special Ack message (positive acknowledgement) or a Failure (negative +acknowledgement). + +**Scala** + +.. code-block:: scala + + import akka.camel.{Ack, Failure} + // ... other imports omitted + + class Consumer3 extends Actor with Consumer { + override def autoack = false + + def endpointUri = "jms:queue:test" + + def receive = { + // ... + self.reply(Ack) // on success + // ... + self.reply(Failure(...)) // on failure + } + } + +**Java** + +.. code-block:: java + + import akka.camel.Failure + import static akka.camel.Ack.ack; + // ... other imports omitted + + public class Consumer3 extends UntypedConsumerActor { + + public String getEndpointUri() { + return "jms:queue:test"; + } + + public boolean isAutoack() { + return false; + } + + public void onReceive(Object message) { + // ... + getContext().replyUnsafe(ack()) // on success + // ... + val e: Exception = ... + getContext().replyUnsafe(new Failure(e)) // on failure + } + } + + +.. _camel-blocking-exchanges: + +Blocking exchanges +------------------ + +By default, message exchanges between a Camel endpoint and a consumer actor are +non-blocking because, internally, the ! (bang) operator is used to commicate +with the actor. The route to the actor does not block waiting for a reply. The +reply is sent asynchronously (see also :ref:`camel-asynchronous-routing`). +Consumer actors however can be configured to make this interaction blocking. + +**Scala** + +.. code-block:: scala + + class ExampleConsumer extends Actor with Consumer { + override def blocking = true + + def endpointUri = ... + def receive = { + // ... + } + } + +**Java** + +.. code-block:: java + + public class ExampleConsumer extends UntypedConsumerActor { + + public boolean isBlocking() { + return true; + } + + public String getEndpointUri() { + // ... + } + + public void onReceive(Object message) { + // ... + } + } + +In this case, the ``!!`` (bangbang) operator is used internally to communicate +with the actor which blocks a thread until the consumer sends a response or +throws an exception within receive. Although it may decrease scalability, this +setting can simplify error handling (see `this article`_) or allows timeout +configurations on actor-level (see :ref:`camel-timeout`). + +.. _this article: http://krasserm.blogspot.com/2011/02/akka-consumer-actors-new-features-and.html + + +.. _camel-timeout: + +Consumer timeout +---------------- + +Endpoints that support two-way communications need to wait for a response from +an (untyped) actor or typed actor before returning it to the initiating client. +For some endpoint types, timeout values can be defined in an endpoint-specific +way which is described in the documentation of the individual `Camel +components`_. Another option is to configure timeouts on the level of consumer +actors and typed consumer actors. + +.. _Camel components: http://camel.apache.org/components.html + + +Typed actors +^^^^^^^^^^^^ + +For typed actors, timeout values for method calls that return a result can be +set when the typed actor is created. In the following example, the timeout is +set to 20 seconds (default is 5 seconds). + +**Scala** + +.. code-block:: scala + + import akka.actor.TypedActor + + val consumer = TypedActor.newInstance(classOf[TypedConsumer1], classOf[TypedConumer1Impl], 20000 /* 20 seconds */) + +**Java** + +.. code-block:: java + + import akka.actor.TypedActor; + + TypedConsumer1 consumer = TypedActor.newInstance(TypedConsumer1.class, TypedConumer1Impl.class, 20000 /* 20 seconds */); + + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +Two-way communications between a Camel endpoint and an (untyped) actor are +initiated by sending the request message to the actor with the ``!`` (bang) +operator and the actor replies to the endpoint when the response is ready. In +order to support timeouts on actor-level, endpoints need to send the request +message with the ``!!`` (bangbang) operator for which a timeout value is +applicable. This can be achieved by overriding the Consumer.blocking method to +return true. + +**Scala** + +.. code-block:: scala + + class Consumer2 extends Actor with Consumer { + self.timeout = 20000 // timeout set to 20 seconds + + override def blocking = true + + def endpointUri = "direct:example" + + def receive = { + // ... + } + } + +**Java** + +.. code-block:: java + + public class Consumer2 extends UntypedConsumerActor { + + public Consumer2() { + getContext().setTimeout(20000); // timeout set to 20 seconds + } + + public String getEndpointUri() { + return "direct:example"; + } + + public boolean isBlocking() { + return true; + } + + public void onReceive(Object message) { + // ... + } + } + +This is a valid approach for all endpoint types that do not "natively" support +asynchronous two-way message exchanges. For all other endpoint types (like +`Jetty`_ endpoints) is it not recommended to switch to blocking mode but rather +to configure timeouts in an endpoint-specific way (see +also :ref:`camel-asynchronous-routing`). + + +Remote consumers +---------------- + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +Publishing of remote consumer actors is always done on the server side, local +proxies are never published. Hence the CamelService must be started on the +remote node. For example, to publish an (untyped) actor on a remote node at +endpoint URI ``jetty:http://localhost:6644/remote-actor-1``, define the +following consumer actor class. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.annotation.consume + import akka.camel.Consumer + + class RemoteActor1 extends Actor with Consumer { + def endpointUri = "jetty:http://localhost:6644/remote-actor-1" + + protected def receive = { + case msg => self.reply("response from remote actor 1") + } + } + +**Java** + +.. code-block:: java + + import akka.camel.UntypedConsumerActor; + + public class RemoteActor1 extends UntypedConsumerActor { + public String getEndpointUri() { + return "jetty:http://localhost:6644/remote-actor-1"; + } + + public void onReceive(Object message) { + getContext().replySafe("response from remote actor 1"); + } + } + +On the remote node, start a `CamelService`_, start a remote server, create the +actor and register it at the remote server. + +.. _CamelService: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/CamelService.scala + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + import akka.actor.Actor._ + import akka.actor.ActorRef + + // ... + startCamelService + + val consumer = val consumer = actorOf[RemoteActor1] + + remote.start("localhost", 7777) + remote.register(consumer) // register and start remote consumer + // ... + +**Java** + +.. code-block:: java + + import akka.camel.CamelServiceManager; + import static akka.actor.Actors.*; + + // ... + CamelServiceManager.startCamelService(); + + ActorRef actor = actorOf(RemoteActor1.class); + + remote().start("localhost", 7777); + remote().register(actor); // register and start remote consumer + // ... + +Explicitly starting a CamelService can be omitted when Akka is running in Kernel +mode, for example (see also :ref:`camel-configuration`). + + +Typed actors +^^^^^^^^^^^^ + +Remote typed consumer actors can be registered with one of the +``registerTyped*`` methods on the remote server. The following example registers +the actor with the custom id "123". + +**Scala** + +.. code-block:: scala + + import akka.actor.TypedActor + + // ... + val obj = TypedActor.newRemoteInstance( + classOf[SampleRemoteTypedConsumer], + classOf[SampleRemoteTypedConsumerImpl]) + + remote.registerTypedActor("123", obj) + // ... + +**Java** + +.. code-block:: java + + import akka.actor.TypedActor; + + SampleRemoteTypedConsumer obj = (SampleRemoteTypedConsumer)TypedActor.newInstance( + SampleRemoteTypedConsumer.class, + SampleRemoteTypedConsumerImpl.class); + + remote.registerTypedActor("123", obj) + // ... + + +Produce messages +================ + +A minimum pre-requisite for producing messages to Camel endpoints with producer +actors (see below) is an initialized and started CamelContextManager. + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelContextManager + + CamelContextManager.init // optionally takes a CamelContext as argument + CamelContextManager.start // starts the managed CamelContext + +**Java** + +.. code-block:: java + + import akka.camel.CamelContextManager; + + CamelContextManager.init(); // optionally takes a CamelContext as argument + CamelContextManager.start(); // starts the managed CamelContext + +For using producer actors, application may also start a CamelService. This will +not only setup a CamelContextManager behind the scenes but also register +listeners at the actor registry (needed to publish consumer actors). If your +application uses producer actors only and you don't want to have the (very +small) overhead generated by the registry listeners then setting up a +CamelContextManager without starting CamelService is recommended. Otherwise, +just start a CamelService as described for consumer +actors: :ref:`camel-consumers-and-camel-service`. + + +Producer trait +-------------- + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +For sending messages to Camel endpoints, actors + +* written in Scala need to mixin the `Producer`_ trait and implement the + endpointUri method. + +* written in Java need to extend the abstract UntypedProducerActor class and + implement the getEndpointUri() method. By extending the UntypedProducerActor + class, untyped actors (Java) inherit the behaviour of the Producer trait. + +.. _Producer: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/Producer.scala + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.Producer + + class Producer1 extends Actor with Producer { + def endpointUri = "http://localhost:8080/news" + } + +**Java** + +.. code-block:: java + + import akka.camel.UntypedProducerActor; + + public class Producer1 extends UntypedProducerActor { + public String getEndpointUri() { + return "http://localhost:8080/news"; + } + } + +Producer1 inherits a default implementation of the receive method from the +Producer trait. To customize a producer actor's default behavior it is +recommended to override the Producer.receiveBeforeProduce and +Producer.receiveAfterProduce methods. This is explained later in more detail. +Actors should not override the default Producer.receive method. + +Any message sent to a Producer actor (or UntypedProducerActor) will be sent to +the associated Camel endpoint, in the above example to +``http://localhost:8080/news``. Response messages (if supported by the +configured endpoint) will, by default, be returned to the original sender. The +following example uses the ``!!`` operator (Scala) to send a message to a +Producer actor and waits for a response. In Java, the sendRequestReply method is +used. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor._ + import akka.actor.ActorRef + + val producer = actorOf[Producer1].start + val response = producer !! "akka rocks" + val body = response.bodyAs[String] + +**Java** + +.. code-block:: java + + import akka.actor.ActorRef; + import static akka.actor.Actors.*; + import akka.camel.Message; + + ActorRef producer = actorOf(Producer1.class).start(); + Message response = (Message)producer.sendRequestReply("akka rocks"); + String body = response.getBodyAs(String.class) + +If the message is sent using the ! operator (or the sendOneWay method in Java) +then the response message is sent back asynchronously to the original sender. In +the following example, a Sender actor sends a message (a String) to a producer +actor using the ! operator and asynchronously receives a response (of type +Message). + +**Scala** + +.. code-block:: scala + + import akka.actor.{Actor, ActorRef} + import akka.camel.Message + + class Sender(producer: ActorRef) extends Actor { + def receive = { + case request: String => producer ! request + case response: Message => { + /* process response ... */ + } + // ... + } + } + +**Java** + +.. code-block:: java + + // TODO + + +.. _camel-custom-processing: + +Custom Processing +^^^^^^^^^^^^^^^^^ + +Instead of replying to the initial sender, producer actors can implement custom +reponse processing by overriding the receiveAfterProduce method (Scala) or +onReceiveAfterProduce method (Java). In the following example, the reponse +message is forwarded to a target actor instead of being replied to the original +sender. + +**Scala** + +.. code-block:: scala + + import akka.actor.{Actor, ActorRef} + import akka.camel.Producer + + class Producer1(target: ActorRef) extends Actor with Producer { + def endpointUri = "http://localhost:8080/news" + + override protected def receiveAfterProduce = { + // do not reply but forward result to target + case msg => target forward msg + } + } + +**Java** + +.. code-block:: java + + import akka.actor.ActorRef; + import akka.camel.UntypedProducerActor; + + public class Producer1 extends UntypedProducerActor { + private ActorRef target; + + public Producer1(ActorRef target) { + this.target = target; + } + + public String getEndpointUri() { + return "http://localhost:8080/news"; + } + + @Override + public void onReceiveAfterProduce(Object message) { + target.forward((Message)message, getContext()); + } + } + +To create an untyped actor instance with a constructor argument, a factory is +needed (this should be doable without a factory in upcoming Akka versions). + +.. code-block:: java + + import akka.actor.ActorRef; + import akka.actor.UntypedActorFactory; + import akka.actor.UntypedActor; + + public class Producer1Factory implements UntypedActorFactory { + + private ActorRef target; + + public Producer1Factory(ActorRef target) { + this.target = target; + } + + public UntypedActor create() { + return new Producer1(target); + } + } + +The instanitation is done with the Actors.actorOf method and the factory as +argument. + +.. code-block:: java + + import static akka.actor.Actors.*; + import akka.actor.ActorRef; + + ActorRef target = ... + ActorRef producer = actorOf(new Producer1Factory(target)); + producer.start(); + +Before producing messages to endpoints, producer actors can pre-process them by +overriding the receiveBeforeProduce method (Scala) or onReceiveBeforeProduce +method (Java). + +**Scala** + +.. code-block:: scala + + import akka.actor.{Actor, ActorRef} + import akka.camel.{Message, Producer} + + class Producer1(target: ActorRef) extends Actor with Producer { + def endpointUri = "http://localhost:8080/news" + + override protected def receiveBeforeProduce = { + case msg: Message => { + // do some pre-processing (e.g. add endpoint-specific message headers) + // ... + + // and return the modified message + msg + } + } + } + +**Java** + +.. code-block:: java + + import akka.actor.ActorRef; + import akka.camel.Message + import akka.camel.UntypedProducerActor; + + public class Producer1 extends UntypedProducerActor { + private ActorRef target; + + public Producer1(ActorRef target) { + this.target = target; + } + + public String getEndpointUri() { + return "http://localhost:8080/news"; + } + + @Override + public Object onReceiveBeforeProduce(Object message) { + Message msg = (Message)message; + // do some pre-processing (e.g. add endpoint-specific message headers) + // ... + + // and return the modified message + return msg + } + } + + +Producer configuration options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The interaction of producer actors with Camel endpoints can be configured to be +one-way or two-way (by initiating in-only or in-out message exchanges, +respectively). By default, the producer initiates an in-out message exchange +with the endpoint. For initiating an in-only exchange, producer actors + +* written in Scala either have to override the oneway method to return true +* written in Java have to override the isOneway method to return true. + +**Scala** + +.. code-block:: scala + + import akka.camel.Producer + + class Producer2 extends Actor with Producer { + def endpointUri = "jms:queue:test" + override def oneway = true + } + +**Java** + +.. code-block:: java + + import akka.camel.UntypedProducerActor; + + public class SampleUntypedReplyingProducer extends UntypedProducerActor { + public String getEndpointUri() { + return "jms:queue:test"; + } + + @Override + public boolean isOneway() { + return true; + } + } + +Message correlation +^^^^^^^^^^^^^^^^^^^ + +To correlate request with response messages, applications can set the +Message.MessageExchangeId message header. + +**Scala** + +.. code-block:: scala + + import akka.camel.Message + + producer ! Message("bar", Map(Message.MessageExchangeId -> "123")) + +**Java** + +.. code-block:: java + + // TODO + +Responses of type Message or Failure will contain that header as well. When +receiving messages from Camel endpoints this message header is already set (see +:ref:`camel-consume-messages`). + + +Matching responses +^^^^^^^^^^^^^^^^^^ + +The following code snippet shows how to best match responses when sending +messages with the !! operator (Scala) or with the sendRequestReply method +(Java). + +**Scala** + +.. code-block:: scala + + val response = producer !! message + + response match { + case Some(Message(body, headers)) => ... + case Some(Failure(exception, headers)) => ... + case _ => ... + } + +**Java** + +.. code-block:: java + + // TODO + + +ProducerTemplate +---------------- + +The `Producer`_ trait (and the abstract UntypedProducerActor class) is a very +convenient way for actors to produce messages to Camel endpoints. (Untyped) +actors and typed actors may also use a Camel `ProducerTemplate`_ for producing +messages to endpoints. For typed actors it's the only way to produce messages to +Camel endpoints. + +At the moment, only the Producer trait fully supports asynchronous in-out +message exchanges with Camel endpoints without allocating a thread for the full +duration of the exchange. For example, when using endpoints that support +asynchronous message exchanges (such as Jetty endpoints that internally use +`Jetty's asynchronous HTTP client`_) then usage of the Producer trait is highly +recommended (see also :ref:`camel-asynchronous-routing`). + +.. _Producer: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/Producer.scala +.. _ProducerTemplate: http://camel.apache.org/maven/camel-2.2.0/camel-core/apidocs/index.html +.. _Jetty's asynchronous HTTP client: http://wiki.eclipse.org/Jetty/Tutorial/HttpClient + + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +A managed ProducerTemplate instance can be obtained via +CamelContextManager.mandatoryTemplate. In the following example, an actor uses a +ProducerTemplate to send a one-way message to a ``direct:news`` endpoint. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.CamelContextManager + + class ProducerActor extends Actor { + protected def receive = { + // one-way message exchange with direct:news endpoint + case msg => CamelContextManager.mandatoryTemplate.sendBody("direct:news", msg) + } + } + +**Java** + +.. code-block:: java + + import akka.actor.UntypedActor; + import akka.camel.CamelContextManager; + + public class SampleUntypedActor extends UntypedActor { + public void onReceive(Object msg) { + CamelContextManager.getMandatoryTemplate().sendBody("direct:news", msg); + } + } + +Alternatively, one can also use ``Option[ProducerTemplate]`` returned by +``CamelContextManager.template``. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.CamelContextManager + + class ProducerActor extends Actor { + protected def receive = { + // one-way message exchange with direct:news endpoint + case msg => for(t <- CamelContextManager.template) t.sendBody("direct:news", msg) + } + } + +**Java** + +.. code-block:: java + + import org.apache.camel.ProducerTemplate + + import akka.actor.UntypedActor; + import akka.camel.CamelContextManager; + + public class SampleUntypedActor extends UntypedActor { + public void onReceive(Object msg) { + for (ProducerTemplate t : CamelContextManager.getTemplate()) { + t.sendBody("direct:news", msg); + } + } + } + +For initiating a a two-way message exchange, one of the +``ProducerTemplate.request*`` methods must be used. + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.CamelContextManager + + class ProducerActor extends Actor { + protected def receive = { + // two-way message exchange with direct:news endpoint + case msg => self.reply(CamelContextManager.mandatoryTemplate.requestBody("direct:news", msg)) + } + } + +**Java** + +.. code-block:: java + + import akka.actor.UntypedActor; + import akka.camel.CamelContextManager; + + public class SampleUntypedActor extends UntypedActor { + public void onReceive(Object msg) { + getContext().replySafe(CamelContextManager.getMandatoryTemplate().requestBody("direct:news", msg)); + } + } + + +Typed actors +^^^^^^^^^^^^ + +Typed Actors get access to a managed ProducerTemplate in the same way, as shown +in the next example. + +**Scala** + +.. code-block:: scala + + // TODO + +**Java** + +.. code-block:: java + + import akka.actor.TypedActor; + import akka.camel.CamelContextManager; + + public class SampleProducerImpl extends TypedActor implements SampleProducer { + public void foo(String msg) { + ProducerTemplate template = CamelContextManager.getMandatoryTemplate(); + template.sendBody("direct:news", msg); + } + } + + +.. _camel-asynchronous-routing: + +Asynchronous routing +==================== + +Since Akka 0.10, in-out message exchanges between endpoints and actors are +designed to be asynchronous. This is the case for both, consumer and producer +actors. + +* A consumer endpoint sends request messages to its consumer actor using the ``!`` + (bang) operator and the actor returns responses with self.reply once they are + ready. The sender reference used for reply is an adapter to Camel's asynchronous + routing engine that implements the ActorRef trait. + +* A producer actor sends request messages to its endpoint using Camel's + asynchronous routing engine. Asynchronous responses are wrapped and added to the + producer actor's mailbox for later processing. By default, response messages are + returned to the initial sender but this can be overridden by Producer + implementations (see also description of the ``receiveAfterProcessing`` method + in :ref:`camel-custom-processing`). + +However, asynchronous two-way message exchanges, without allocating a thread for +the full duration of exchange, cannot be generically supported by Camel's +asynchronous routing engine alone. This must be supported by the individual +`Camel components`_ (from which endpoints are created) as well. They must be +able to suspend any work started for request processing (thereby freeing threads +to do other work) and resume processing when the response is ready. This is +currently the case for a `subset of components`_ such as the `Jetty component`_. +All other Camel components can still be used, of course, but they will cause +allocation of a thread for the duration of an in-out message exchange. There's +also a :ref:`camel-async-example` that implements both, an asynchronous +consumer and an asynchronous producer, with the jetty component. + +.. _Camel components: http://camel.apache.org/components.html +.. _subset of components: http://camel.apache.org/asynchronous-routing-engine.html +.. _Jetty component: http://camel.apache.org/jetty.html + + +Fault tolerance +=============== + +Consumer actors and typed actors can be also managed by supervisors. If a +consumer is configured to be restarted upon failure the associated Camel +endpoint is not restarted. It's behaviour during restart is as follows. + +* A one-way (in-only) message exchange will be queued by the consumer and + processed once restart completes. + +* A two-way (in-out) message exchange will wait and either succeed after restart + completes or time-out when the restart duration exceeds + the :ref:`camel-timeout`. + +If a consumer is configured to be shut down upon failure, the associated +endpoint is shut down as well. For details refer to :ref:`camel-unpublishing`. + +For examples, tips and trick how to implement fault-tolerant consumer and +producer actors, take a look at these two articles. + +* `Akka Consumer Actors: New Features and Best Practices `_ +* `Akka Producer Actors: New Features and Best Practices `_ + + +.. _camel-configuration: + +CamelService configuration +========================== + +For publishing consumer actors and typed actor methods +(:ref:`camel-publishing`), applications must start a CamelService. When starting +Akka in :ref:`microkernel` mode then a CamelService can be started automatically +when camel is added to the enabled-modules list in akka.conf, for example: + +.. code-block:: none + + akka { + ... + enabled-modules = ["camel"] # Options: ["remote", "camel", "http"] + ... + } + +Applications that do not use the Akka Kernel, such as standalone applications +for example, need to start a CamelService manually, as explained in the +following subsections.When starting a CamelService manually, settings in +akka.conf are ignored. + + +Standalone applications +----------------------- + +Standalone application should create and start a CamelService in the following way. + +**Scala** + +.. code-block:: scala + + import akka.camel.CamelServiceManager._ + + startCamelService + +**Java** + +.. code-block:: java + + import static akka.camel.CamelServiceManager.*; + + startCamelService(); + +Internally, a CamelService uses the CamelContextManager singleton to manage a +CamelContext. A CamelContext manages the routes from endpoints to consumer +actors and typed actors. These routes are added and removed at runtime (when +(untyped) consumer actors and typed consumer actors are started and stopped). +Applications may additionally want to add their own custom routes or modify the +CamelContext in some other way. This can be done by initializing the +CamelContextManager manually and making modifications to CamelContext **before** +the CamelService is started. + +**Scala** + +.. code-block:: scala + + import org.apache.camel.builder.RouteBuilder + + import akka.camel.CamelContextManager + import akka.camel.CamelServiceManager._ + + CamelContextManager.init + + // add a custom route to the managed CamelContext + CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder) + + startCamelService + + // an application-specific route builder + class CustomRouteBuilder extends RouteBuilder { + def configure { + // ... + } + } + +**Java** + +.. code-block:: java + + import org.apache.camel.builder.RouteBuilder; + + import akka.camel.CamelContextManager; + import static akka.camel.CamelServiceManager.*; + + CamelContextManager.init(); + + // add a custom route to the managed CamelContext + CamelContextManager.getMandatoryContext().addRoutes(new CustomRouteBuilder()); + + startCamelService(); + + // an application-specific route builder + private static class CustomRouteBuilder extends RouteBuilder { + public void configure() { + // ... + } + } + + +Applications may even provide their own CamelContext instance as argument to the +init method call as shown in the following snippet. Here, a DefaultCamelContext +is created using a Spring application context as `registry`_. + +.. _registry: http://camel.apache.org/registry.html + + +**Scala** + +.. code-block:: scala + + import org.apache.camel.impl.DefaultCamelContext + import org.apache.camel.spring.spi.ApplicationContextRegistry + import org.springframework.context.support.ClassPathXmlApplicationContext + + import akka.camel.CamelContextManager + import akka.camel.CamelServiceManager._ + + // create a custom Camel registry backed up by a Spring application context + val context = new ClassPathXmlApplicationContext("/context.xml") + val registry = new ApplicationContextRegistry(context) + + // initialize CamelContextManager with a DefaultCamelContext using the custom registry + CamelContextManager.init(new DefaultCamelContext(registry)) + + // ... + + startCamelService + +**Java** + +.. code-block:: java + + import org.apache.camel.impl.DefaultCamelContext + import org.apache.camel.spi.Registry; + import org.apache.camel.spring.spi.ApplicationContextRegistry; + + import org.springframework.context.ApplicationContext; + import org.springframework.context.support.ClassPathXmlApplicationContext; + + import akka.camel.CamelContextManager; + import static akka.camel.CamelServiceManager.*; + + // create a custom Camel registry backed up by a Spring application context + ApplicationContext context = new ClassPathXmlApplicationContext("/context.xml"); + Registry registry = new ApplicationContextRegistry(context); + + // initialize CamelContextManager with a DefaultCamelContext using the custom registry + CamelContextManager.init(new DefaultCamelContext(registry)); + + // ... + + startCamelService(); + + +.. _camel-spring-applications: + +Standalone Spring applications +------------------------------ + +A better approach to configure a Spring application context as registry for the +CamelContext is to use `Camel's Spring support`_. Furthermore, +the :ref:`spring-module` module additionally supports a element +for creating and starting a CamelService. An optional reference to a custom +CamelContext can be defined for as well. Here's an example. + +.. _Camel's Spring support: http://camel.apache.org/spring.html + +.. code-block:: xml + + + + + + + + + + + + + + + + + +Creating a CamelContext this way automatically adds the defining Spring +application context as registry to that CamelContext. The CamelService is +started when the application context is started and stopped when the application +context is closed. A simple usage example is shown in the following snippet. + +**Scala** + +.. code-block:: scala + + import org.springframework.context.support.ClassPathXmlApplicationContext + import akka.camel.CamelContextManager + + // Create and start application context (start CamelService) + val appctx = new ClassPathXmlApplicationContext("/context.xml") + + // Access to CamelContext (SpringCamelContext) + val ctx = CamelContextManager.mandatoryContext + // Access to ProducerTemplate of that CamelContext + val tpl = CamelContextManager.mandatoryTemplate + + // use ctx and tpl ... + + // Close application context (stop CamelService) + appctx.close + +**Java** + +.. code-block:: java + + // TODO + + +If the CamelService doesn't reference a custom CamelContext then a +DefaultCamelContext is created (and accessible via the CamelContextManager). + +.. code-block:: xml + + + + + + + + + +Kernel mode +----------- + +For classes that are loaded by the Kernel or the Initializer, starting the +CamelService can be omitted, as discussed in the previous section. Since these +classes are loaded and instantiated before the CamelService is started (by +Akka), applications can make modifications to a CamelContext here as well (and +even provide their own CamelContext). Assuming there's a boot class +sample.camel.Boot configured in akka.conf. + +.. code-block:: none + + akka { + ... + boot = ["sample.camel.Boot"] + ... + } + +Modifications to the CamelContext can be done like in the following snippet. + +**Scala** + +.. code-block:: scala + + package sample.camel + + import org.apache.camel.builder.RouteBuilder + + import akka.camel.CamelContextManager + + class Boot { + CamelContextManager.init + + // Customize CamelContext with application-specific routes + CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder) + + // No need to start CamelService here. It will be started + // when this classes has been loaded and instantiated. + } + + class CustomRouteBuilder extends RouteBuilder { + def configure { + // ... + } + } + +**Java** + +.. code-block:: java + + // TODO + + +Custom Camel routes +=================== + +In all the examples so far, routes to consumer actors have been automatically +constructed by akka-camel, when the actor was started. Although the default +route construction templates, used by akka-camel internally, are sufficient for +most use cases, some applications may require more specialized routes to actors. +The akka-camel module provides two mechanisms for customizing routes to actors, +which will be explained in this section. These are + +* Usage of :ref:`camel-components` to access (untyped) actor and actors. + Any Camel route can use these components to access Akka actors. + +* :ref:`camel-intercepting-route-construction` to (untyped) actor and actors. + Default routes to consumer actors are extended using predefined extension + points. + + +.. _camel-components: + +Akka Camel components +--------------------- + +Akka actors can be access from Camel routes using the `actor`_ and +`typed-actor`_ Camel components, respectively. These components can be used to +access any Akka actor (not only consumer actors) from Camel routes, as described +in the following sections. + +.. _actor: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala +.. _typed-actor: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/component/TypedActorComponent.scala + + +Access to actors +---------------- + +To access (untyped) actors from custom Camel routes, the `actor`_ Camel +component should be used. It fully supports Camel's `asynchronous routing +engine`_. + +.. _actor: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/component/ActorComponent.scala +.. _asynchronous routing engine: http://camel.apache.org/asynchronous-routing-engine.html + +This component accepts the following enpoint URI formats: + +* ``actor:[?]`` +* ``actor:id:[][?]`` +* ``actor:uuid:[][?]`` + +where ```` and ```` refer to ``actorRef.id`` and the +String-representation of ``actorRef.uuid``, respectively. The ```` are +name-value pairs separated by ``&`` (i.e. ``name1=value1&name2=value2&...``). + + +URI options +^^^^^^^^^^^ + +The following URI options are supported: + ++----------+---------+---------+-------------------------------------------+ +| Name | Type | Default | Description | ++==========+=========+=========+===========================================+ +| blocking | Boolean | false | If set to true, in-out message exchanges | +| | | | with the target actor will be made with | +| | | | the ``!!`` operator, otherwise with the | +| | | | ``!`` operator. | +| | | | | +| | | | See also :ref:`camel-timeout`. | ++----------+---------+---------+-------------------------------------------+ +| autoack | Boolean | true | If set to true, in-only message exchanges | +| | | | are auto-acknowledged when the message is | +| | | | added to the actor's mailbox. If set to | +| | | | false, actors must acknowledge the | +| | | | receipt of the message. | +| | | | | +| | | | See also :ref:`camel-acknowledgements`. | ++----------+---------+---------+-------------------------------------------+ + +Here's an actor endpoint URI example containing an actor uuid:: + + actor:uuid:12345678?blocking=true + +In actor endpoint URIs that contain id: or uuid:, an actor identifier (id or +uuid) is optional. In this case, the in-message of an exchange produced to an +actor endpoint must contain a message header with name CamelActorIdentifier +(which is defined by the ActorComponent.ActorIdentifier field) and a value that +is the target actor's identifier. On the other hand, if the URI contains an +actor identifier, it can be seen as a default actor identifier that can be +overridden by messages containing a CamelActorIdentifier header. + + +Message headers +^^^^^^^^^^^^^^^ + ++----------------------+--------+-------------------------------------------+ +| Name | Type | Description | ++======================+========+===========================================+ +| CamelActorIdentifier | String | Contains the identifier (id or uuid) of | +| | | the actor to route the message to. The | +| | | identifier is interpreted as actor id if | +| | | the URI contains id:, the identifier is | +| | | interpreted as uuid id the URI contains | +| | | uuid:. A uuid value may also be of type | +| | | Uuid (not only String). The header name | +| | | is defined by the | +| | | ActorComponent.ActorIdentifier field. | ++----------------------+--------+-------------------------------------------+ + +Here's another actor endpoint URI example that doesn't define an actor uuid. In +this case the target actor uuid must be defined by the CamelActorIdentifier +message header:: + + actor:uuid: + +In the following example, a custom route to an actor is created, using the +actor's uuid (i.e. actorRef.uuid). The route starts from a `Jetty`_ endpoint and +ends at the target actor. + + +**Scala** + +.. code-block:: scala + + import org.apache.camel.builder.RouteBuilder + + import akka.actor._ + import akka.actor.Actor + import akka.actor.Actor._ + import akka.camel.{Message, CamelContextManager, CamelServiceManager} + + object CustomRouteExample extends Application { + val target = actorOf[CustomRouteTarget].start + + CamelServiceManager.startCamelService + CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder(target.uuid)) + } + + class CustomRouteTarget extends Actor { + def receive = { + case msg: Message => self.reply("Hello %s" format msg.bodyAs[String]) + } + } + + class CustomRouteBuilder(uuid: Uuid) extends RouteBuilder { + def configure { + val actorUri = "actor:uuid:%s" format uuid + from("jetty:http://localhost:8877/camel/custom").to(actorUri) + } + } + + +**Java** + +.. code-block:: java + + import com.eaio.uuid.UUID; + + import org.apache.camel.builder.RouteBuilder; + import static akka.actor.Actors.*; + import akka.actor.ActorRef; + import akka.actor.UntypedActor; + import akka.camel.CamelServiceManager; + import akka.camel.CamelContextManager; + import akka.camel.Message; + + public class CustomRouteExample { + public static void main(String... args) throws Exception { + ActorRef target = actorOf(CustomRouteTarget.class).start(); + CamelServiceManager.startCamelService(); + CamelContextManager.getMandatoryContext().addRoutes(new CustomRouteBuilder(target.getUuid())); + } + } + + public class CustomRouteTarget extends UntypedActor { + public void onReceive(Object message) { + Message msg = (Message) message; + String body = msg.getBodyAs(String.class); + getContext().replySafe(String.format("Hello %s", body)); + } + } + + public class CustomRouteBuilder extends RouteBuilder { + private UUID uuid; + + public CustomRouteBuilder(UUID uuid) { + this.uuid = uuid; + } + + public void configure() { + String actorUri = String.format("actor:uuid:%s", uuid); + from("jetty:http://localhost:8877/camel/custom").to(actorUri); + } + } + +When the example is started, messages POSTed to +``http://localhost:8877/camel/custom`` are routed to the target actor. + + +Access to typed actors +---------------------- + +To access typed actor methods from custom Camel routes, the `typed-actor`_ Camel +component should be used. It is a specialization of the Camel `bean`_ component. +Applications should use the interface (endpoint URI syntax and options) as +described in the bean component documentation but with the typed-actor schema. +Typed Actors must be added to a `Camel registry`_ for being accessible by the +typed-actor component. + +.. _typed-actor: http://github.com/jboner/akka-modules/blob/master/akka-camel/src/main/scala/akka/camel/component/TypedActorComponent.scala +.. _bean: http://camel.apache.org/bean.html +.. _Camel registry: http://camel.apache.org/registry.html + + +.. _camel-typed-actors-using-spring: + +Using Spring +^^^^^^^^^^^^ + +The following example shows how to access typed actors in a Spring application +context. For adding typed actors to the application context and for starting +:ref:`camel-spring-applications` the :ref:`spring-module` module is used in the +following example. It offers a ```` element to define typed actor +factory beans and a ```` element to create and start a +CamelService. + +.. code-block:: xml + + + + + + + + + + + + + + + + + +SampleTypedActor is the typed actor interface and SampleTypedActorImpl in the +typed actor implementation class. + +**Scala** + +.. code-block:: scala + + package sample + + import akka.actor.TypedActor + + trait SampleTypedActor { + def foo(s: String): String + } + + class SampleTypedActorImpl extends TypedActor with SampleTypedActor { + def foo(s: String) = "hello %s" format s + } + +**Java** + +.. code-block:: java + + package sample; + + import akka.actor.TypedActor; + + public interface SampleTypedActor { + public String foo(String s); + } + + public class SampleTypedActorImpl extends TypedActor implements SampleTypedActor { + + public String foo(String s) { + return "hello " + s; + } + } + +The SampleRouteBuilder defines a custom route from the direct:test endpoint to +the sample typed actor using a typed-actor endpoint URI. + +**Scala** + +.. code-block:: scala + + package sample + + import org.apache.camel.builder.RouteBuilder + + class SampleRouteBuilder extends RouteBuilder { + def configure = { + // route to typed actor + from("direct:test").to("typed-actor:sample?method=foo") + } + } + +**Java** + +.. code-block:: java + + package sample; + + import org.apache.camel.builder.RouteBuilder; + + public class SampleRouteBuilder extends RouteBuilder { + public void configure() { + // route to typed actor + from("direct:test").to("typed-actor:sample?method=foo"); + } + } + +The typed-actor endpoint URI syntax is::: + + typed-actor:?method= + +where ```` is the id of the bean in the Spring application context and +```` is the name of the typed actor method to invoke. + +Usage of the custom route for sending a message to the typed actor is shown in +the following snippet. + +**Scala** + +.. code-block:: scala + + package sample + + import org.springframework.context.support.ClassPathXmlApplicationContext + import akka.camel.CamelContextManager + + // load Spring application context (starts CamelService) + val appctx = new ClassPathXmlApplicationContext("/context-standalone.xml") + + // access 'sample' typed actor via custom route + assert("hello akka" == CamelContextManager.mandatoryTemplate.requestBody("direct:test", "akka")) + + // close Spring application context (stops CamelService) + appctx.close + +**Java** + +.. code-block:: java + + package sample; + + import org.springframework.context.support.ClassPathXmlApplicationContext; + import akka.camel.CamelContextManager; + + // load Spring application context + ClassPathXmlApplicationContext appctx = new ClassPathXmlApplicationContext("/context-standalone.xml"); + + // access 'externally' registered typed actors with typed-actor component + assert("hello akka" == CamelContextManager.getMandatoryTemplate().requestBody("direct:test", "akka")); + + // close Spring application context (stops CamelService) + appctx.close(); + +The application uses a Camel `producer template`_ to access the typed actor via +the ``direct:test`` endpoint. + +.. _producer template: http://camel.apache.org/producertemplate.html + + +Without Spring +^^^^^^^^^^^^^^ + +Usage of :ref:`spring-module` for adding typed actors to the Camel registry and +starting a CamelService is optional. Setting up a Spring-less application for +accessing typed actors is shown in the next example. + +**Scala** + +.. code-block:: scala + + package sample + + import org.apache.camel.impl.{DefaultCamelContext, SimpleRegistry} + import akka.actor.TypedActor + import akka.camel.CamelContextManager + import akka.camel.CamelServiceManager._ + + // register typed actor + val registry = new SimpleRegistry + registry.put("sample", TypedActor.newInstance(classOf[SampleTypedActor], classOf[SampleTypedActorImpl])) + + // customize CamelContext + CamelContextManager.init(new DefaultCamelContext(registry)) + CamelContextManager.mandatoryContext.addRoutes(new SampleRouteBuilder) + + startCamelService + + // access 'sample' typed actor via custom route + assert("hello akka" == CamelContextManager.mandatoryTemplate.requestBody("direct:test", "akka")) + + stopCamelService + +**Java** + +.. code-block:: java + + package sample; + + // register typed actor + SimpleRegistry registry = new SimpleRegistry(); + registry.put("sample", TypedActor.newInstance(SampleTypedActor.class, SampleTypedActorImpl.class)); + + // customize CamelContext + CamelContextManager.init(new DefaultCamelContext(registry)); + CamelContextManager.getMandatoryContext().addRoutes(new SampleRouteBuilder()); + + startCamelService(); + + // access 'sample' typed actor via custom route + assert("hello akka" == CamelContextManager.getMandatoryTemplate().requestBody("direct:test", "akka")); + + stopCamelService(); + +Here, `SimpleRegistry`_, a java.util.Map based registry, is used to register +typed actors. The CamelService is started and stopped programmatically. + +.. _SimpleRegistry: https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/SimpleRegistry.java + + +.. _camel-intercepting-route-construction: + +Intercepting route construction +------------------------------- + +The previous section, :ref:`camel-components`, explained how to setup a route to +an (untyped) actor or typed actor manually. It was the application's +responsibility to define the route and add it to the current CamelContext. This +section explains a more conventient way to define custom routes: akka-camel is +still setting up the routes to consumer actors (and adds these routes to the +current CamelContext) but applications can define extensions to these routes. +Extensions can be defined with Camel's `Java DSL`_ or `Scala DSL`_. For example, +an extension could be a custom error handler that redelivers messages from an +endpoint to an actor's bounded mailbox when the mailbox was full. + +.. _Java DSL: http://camel.apache.org/dsl.html +.. _Scala DSL: http://camel.apache.org/scala-dsl.html + +The following examples demonstrate how to extend a route to a consumer actor for +handling exceptions thrown by that actor. To simplify the example, we configure +:ref:`camel-blocking-exchanges` which reports any exception, that is thrown by +receive, directly back to the Camel route. One could also report exceptions +asynchronously using a Failure reply (see also `this article`__) but we'll do it +differently here. + +__ http://krasserm.blogspot.com/2011/02/akka-consumer-actors-new-features-and.html + + +Actors (untyped) +^^^^^^^^^^^^^^^^ + +**Scala** + +.. code-block:: scala + + import akka.actor.Actor + import akka.camel.Consumer + + import org.apache.camel.builder.Builder + import org.apache.camel.model.RouteDefinition + + class ErrorHandlingConsumer extends Actor with Consumer { + def endpointUri = "direct:error-handler-test" + + // Needed to propagate exception back to caller + override def blocking = true + + onRouteDefinition {rd: RouteDefinition => + // Catch any exception and handle it by returning the exception message as response + rd.onException(classOf[Exception]).handled(true).transform(Builder.exceptionMessage).end + } + + protected def receive = { + case msg: Message => throw new Exception("error: %s" format msg.body) + } + } + +**Java** + +.. code-block:: java + + import akka.camel.UntypedConsumerActor; + + import org.apache.camel.builder.Builder; + import org.apache.camel.model.ProcessorDefinition; + import org.apache.camel.model.RouteDefinition; + + public class SampleErrorHandlingConsumer extends UntypedConsumerActor { + + public String getEndpointUri() { + return "direct:error-handler-test"; + } + + // Needed to propagate exception back to caller + public boolean isBlocking() { + return true; + } + + public void preStart() { + onRouteDefinition(new RouteDefinitionHandler() { + public ProcessorDefinition onRouteDefinition(RouteDefinition rd) { + // Catch any exception and handle it by returning the exception message as response + return rd.onException(Exception.class).handled(true).transform(Builder.exceptionMessage()).end(); + } + }); + } + + public void onReceive(Object message) throws Exception { + Message msg = (Message)message; + String body = msg.getBodyAs(String.class); + throw new Exception(String.format("error: %s", body)); + } + + } + + + +For (untyped) actors, consumer route extensions are defined by calling the +onRouteDefinition method with a route definition handler. In Scala, this is a +function of type ``RouteDefinition => ProcessorDefinition[_]``, in Java it is an +instance of ``RouteDefinitionHandler`` which is defined as follows. + +.. code-block:: scala + + package akka.camel + + import org.apache.camel.model.RouteDefinition + import org.apache.camel.model.ProcessorDefinition + + trait RouteDefinitionHandler { + def onRouteDefinition(rd: RouteDefinition): ProcessorDefinition[_] + } + +The akka-camel module creates a RouteDefinition instance by calling +from(endpointUri) on a Camel RouteBuilder (where endpointUri is the endpoint URI +of the consumer actor) and passes that instance as argument to the route +definition handler \*). The route definition handler then extends the route and +returns a ProcessorDefinition (in the above example, the ProcessorDefinition +returned by the end method. See the `org.apache.camel.model`__ package for +details). After executing the route definition handler, akka-camel finally calls +a to(actor:uuid:actorUuid) on the returned ProcessorDefinition to complete the +route to the comsumer actor (where actorUuid is the uuid of the consumer actor). + +\*) Before passing the RouteDefinition instance to the route definition handler, +akka-camel may make some further modifications to it. + +__ https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/main/java/org/apache/camel/model/ + + +Typed actors +^^^^^^^^^^^^ + +For typed consumer actors to define a route definition handler, they must +provide a RouteDefinitionHandler implementation class with the @consume +annotation. The implementation class must have a no-arg constructor. Here's an +example (in Java). + +.. code-block:: java + + import org.apache.camel.builder.Builder; + import org.apache.camel.model.ProcessorDefinition; + import org.apache.camel.model.RouteDefinition; + + public class SampleRouteDefinitionHandler implements RouteDefinitionHandler { + public ProcessorDefinition onRouteDefinition(RouteDefinition rd) { + return rd.onException(Exception.class).handled(true).transform(Builder.exceptionMessage()).end(); + } + } + +It can be used as follows. + +**Scala** + +.. code-block:: scala + + trait TestTypedConsumer { + @consume(value="direct:error-handler-test", routeDefinitionHandler=classOf[SampleRouteDefinitionHandler]) + def foo(s: String): String + } + + // implementation class omitted + +**Java** + +.. code-block:: java + + public interface SampleErrorHandlingTypedConsumer { + + @consume(value="direct:error-handler-test", routeDefinitionHandler=SampleRouteDefinitionHandler.class) + String foo(String s); + + } + + // implementation class omitted + + +.. _camel-examples: + +Examples +======== + +For all features described so far, there's running sample code in +`akka-sample-camel`_. The examples in `sample.camel.Boot`_ are started during +Kernel startup because this class has been added to the boot configuration in +akka-reference.conf. + +.. _akka-sample-camel: http://github.com/jboner/akka-modules/tree/master/akka-modules-samples/akka-sample-camel/ +.. _sample.camel.Boot: http://github.com/jboner/akka-modules/blob/master/akka-modules-samples/akka-sample-camel/src/main/scala/sample/camel/Boot.scala + +.. code-block:: none + + akka { + ... + boot = ["sample.camel.Boot", ...] + ... + } + +If you don't want to have these examples started during Kernel startup, delete +it from akka-reference.conf (or from akka.conf if you have a custom boot +configuration). Other examples are standalone applications (i.e. classes with a +main method) that can be started from `sbt`_. + +.. _sbt: http://code.google.com/p/simple-build-tool/ + +.. code-block:: none + + $ sbt + [info] Building project akka-modules 2.0-SNAPSHOT against Scala 2.9.0 + [info] using AkkaModulesParentProject with sbt 0.7.7 and Scala 2.7.7 + > project akka-sample-camel + Set current project to akka-sample-camel 2.0-SNAPSHOT + > run + ... + Multiple main classes detected, select one to run: + + [1] sample.camel.ClientApplication + [2] sample.camel.ServerApplication + [3] sample.camel.StandaloneSpringApplication + [4] sample.camel.StandaloneApplication + [5] sample.camel.StandaloneFileApplication + [6] sample.camel.StandaloneJmsApplication + + +Some of the examples in `akka-sample-camel`_ are described in more detail in the +following subsections. + + +.. _camel-async-example: + +Asynchronous routing and transformation example +----------------------------------------------- + +This example demonstrates how to implement consumer and producer actors that +support :ref:`camel-asynchronous-routing` with their Camel endpoints. The sample +application transforms the content of the Akka homepage, http://akka.io, by +replacing every occurrence of *Akka* with *AKKA*. After starting +the :ref:`microkernel`, direct the browser to http://localhost:8875 and the +transformed Akka homepage should be displayed. Please note that this example +will probably not work if you're behind an HTTP proxy. + +The following figure gives an overview how the example actors interact with +external systems and with each other. A browser sends a GET request to +http://localhost:8875 which is the published endpoint of the ``HttpConsumer`` +actor. The ``HttpConsumer`` actor forwards the requests to the ``HttpProducer`` +actor which retrieves the Akka homepage from http://akka.io. The retrieved HTML +is then forwarded to the ``HttpTransformer`` actor which replaces all occurences +of *Akka* with *AKKA*. The transformation result is sent back the HttpConsumer +which finally returns it to the browser. + +.. image:: camel-async-interact.png + +Implementing the example actor classes and wiring them together is rather easy +as shown in the following snippet (see also `sample.camel.Boot`_). + +.. code-block:: scala + + import org.apache.camel.Exchange + import akka.actor.Actor._ + import akka.actor.{Actor, ActorRef} + import akka.camel.{Producer, Message, Consumer} + + class HttpConsumer(producer: ActorRef) extends Actor with Consumer { + def endpointUri = "jetty:http://0.0.0.0:8875/" + + protected def receive = { + case msg => producer forward msg + } + } + + class HttpProducer(transformer: ActorRef) extends Actor with Producer { + def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" + + override protected def receiveBeforeProduce = { + // only keep Exchange.HTTP_PATH message header (which needed by bridge endpoint) + case msg: Message => msg.setHeaders(msg.headers(Set(Exchange.HTTP_PATH))) + } + + override protected def receiveAfterProduce = { + // do not reply but forward result to transformer + case msg => transformer forward msg + } + } + + class HttpTransformer extends Actor { + protected def receive = { + case msg: Message => self.reply(msg.transformBody {body: String => body replaceAll ("Akka ", "AKKA ")}) + case msg: Failure => self.reply(msg) + } + } + + // Wire and start the example actors + val httpTransformer = actorOf(new HttpTransformer).start + val httpProducer = actorOf(new HttpProducer(httpTransformer)).start + val httpConsumer = actorOf(new HttpConsumer(httpProducer)).start + +The `jetty endpoints`_ of HttpConsumer and HttpProducer support asynchronous +in-out message exchanges and do not allocate threads for the full duration of +the exchange. This is achieved by using `Jetty continuations`_ on the +consumer-side and by using `Jetty's asynchronous HTTP client`_ on the producer +side. The following high-level sequence diagram illustrates that. + +.. _jetty endpoints: http://camel.apache.org/jetty.html +.. _Jetty continuations: http://wiki.eclipse.org/Jetty/Feature/Continuations +.. _Jetty's asynchronous HTTP client: http://wiki.eclipse.org/Jetty/Tutorial/HttpClient + +.. image:: camel-async-sequence.png + + +Custom Camel route example +-------------------------- + +This section also demonstrates the combined usage of a ``Producer`` and a +``Consumer`` actor as well as the inclusion of a custom Camel route. The +following figure gives an overview. + +.. image:: camel-custom-route.png + +* A consumer actor receives a message from an HTTP client + +* It forwards the message to another actor that transforms the message (encloses + the original message into hyphens) + +* The transformer actor forwards the transformed message to a producer actor + +* The producer actor sends the message to a custom Camel route beginning at the + ``direct:welcome`` endpoint + +* A processor (transformer) in the custom Camel route prepends "Welcome" to the + original message and creates a result message + +* The producer actor sends the result back to the consumer actor which returns + it to the HTTP client + + +The example is part of `sample.camel.Boot`_. The consumer, transformer and +producer actor implementations are as follows. + +.. code-block:: scala + + package sample.camel + + import akka.actor.{Actor, ActorRef} + import akka.camel.{Message, Consumer} + + class Consumer3(transformer: ActorRef) extends Actor with Consumer { + def endpointUri = "jetty:http://0.0.0.0:8877/camel/welcome" + + def receive = { + // Forward a string representation of the message body to transformer + case msg: Message => transformer.forward(msg.setBodyAs[String]) + } + } + + class Transformer(producer: ActorRef) extends Actor { + protected def receive = { + // example: transform message body "foo" to "- foo -" and forward result to producer + case msg: Message => producer.forward(msg.transformBody((body: String) => "- %s -" format body)) + } + } + + class Producer1 extends Actor with Producer { + def endpointUri = "direct:welcome" + } + +The producer actor knows where to reply the message to because the consumer and +transformer actors have forwarded the original sender reference as well. The +application configuration and the route starting from direct:welcome are as +follows. + +.. code-block:: scala + + package sample.camel + + import org.apache.camel.builder.RouteBuilder + import org.apache.camel.{Exchange, Processor} + + import akka.actor.Actor._ + import akka.camel.CamelContextManager + + class Boot { + CamelContextManager.init() + CamelContextManager.mandatoryContext.addRoutes(new CustomRouteBuilder) + + val producer = actorOf[Producer1] + val mediator = actorOf(new Transformer(producer)) + val consumer = actorOf(new Consumer3(mediator)) + + producer.start + mediator.start + consumer.start + } + + class CustomRouteBuilder extends RouteBuilder { + def configure { + from("direct:welcome").process(new Processor() { + def process(exchange: Exchange) { + // Create a 'welcome' message from the input message + exchange.getOut.setBody("Welcome %s" format exchange.getIn.getBody) + } + }) + } + } + +To run the example, start the :ref:`microkernel` and POST a message to +``http://localhost:8877/camel/welcome``. + +.. code-block:: none + + curl -H "Content-Type: text/plain" -d "Anke" http://localhost:8877/camel/welcome + +The response should be: + +.. code-block:: none + + Welcome - Anke - + + +Publish-subcribe example +------------------------ + +JMS +^^^ + +This section demonstrates how akka-camel can be used to implement +publish/subscribe for actors. The following figure sketches an example for +JMS-based publish/subscribe. + +.. image:: camel-pubsub.png + +A consumer actor receives a message from an HTTP client. It sends the message to +a JMS producer actor (publisher). The JMS producer actor publishes the message +to a JMS topic. Two other actors that subscribed to that topic both receive the +message. The actor classes used in this example are shown in the following +snippet. + +.. code-block:: scala + + package sample.camel + + import akka.actor.{Actor, ActorRef} + import akka.camel.{Producer, Message, Consumer} + + class Subscriber(name:String, uri: String) extends Actor with Consumer { + def endpointUri = uri + + protected def receive = { + case msg: Message => println("%s received: %s" format (name, msg.body)) + } + } + + class Publisher(name: String, uri: String) extends Actor with Producer { + self.id = name + + def endpointUri = uri + + // one-way communication with JMS + override def oneway = true + } + + class PublisherBridge(uri: String, publisher: ActorRef) extends Actor with Consumer { + def endpointUri = uri + + protected def receive = { + case msg: Message => { + publisher ! msg.bodyAs[String] + self.reply("message published") + } + } + } + +Wiring these actors to implement the above example is as simple as + +.. code-block:: scala + + package sample.camel + + import org.apache.camel.impl.DefaultCamelContext + import org.apache.camel.spring.spi.ApplicationContextRegistry + import org.springframework.context.support.ClassPathXmlApplicationContext + + import akka.actor.Actor._ + import akka.camel.CamelContextManager + + class Boot { + // Create CamelContext with Spring-based registry and custom route builder + val context = new ClassPathXmlApplicationContext("/context-jms.xml", getClass) + val registry = new ApplicationContextRegistry(context) + CamelContextManager.init(new DefaultCamelContext(registry)) + + // Setup publish/subscribe example + val jmsUri = "jms:topic:test" + val jmsSubscriber1 = actorOf(new Subscriber("jms-subscriber-1", jmsUri)).start + val jmsSubscriber2 = actorOf(new Subscriber("jms-subscriber-2", jmsUri)).start + val jmsPublisher = actorOf(new Publisher("jms-publisher", jmsUri)).start + + val jmsPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/jms", jmsPublisher)).start + } + +To publish messages to subscribers one could of course also use the JMS API +directly; there's no need to do that over a JMS producer actor as in this +example. For the example to work, Camel's `jms`_ component needs to be +configured with a JMS connection factory which is done in a Spring application +context XML file (context-jms.xml). + +.. _jms: http://camel.apache.org/jms.html + +.. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + +To run the example, start the :ref:`microkernel` and POST a +message to ``http://localhost:8877/camel/pub/jms``. + +.. code-block:: none + + curl -H "Content-Type: text/plain" -d "Happy hAkking" http://localhost:8877/camel/pub/jms + +The HTTP response body should be + +.. code-block:: none + + message published + +On the console, where you started the Akka Kernel, you should see something like + +.. code-block:: none + + ... + INF [20100622-11:49:57.688] camel: jms-subscriber-2 received: Happy hAkking + INF [20100622-11:49:57.688] camel: jms-subscriber-1 received: Happy hAkking + + +Cometd +^^^^^^ + +Publish/subscribe with `CometD`_ is equally easy using `Camel's cometd +component`_. + +.. _CometD: http://cometd.org/ +.. _Camel's cometd component: http://camel.apache.org/cometd.html + +.. image:: camel-pubsub2.png + +All actor classes from the JMS example can re-used, only the endpoint URIs need +to be changed. + +.. code-block:: scala + + package sample.camel + + import org.apache.camel.impl.DefaultCamelContext + import org.apache.camel.spring.spi.ApplicationContextRegistry + import org.springframework.context.support.ClassPathXmlApplicationContext + + import akka.actor.Actor._ + import akka.camel.CamelContextManager + + class Boot { + // ... + + // Setup publish/subscribe example + val cometdUri = "cometd://localhost:8111/test/abc?resourceBase=target" + val cometdSubscriber = actorOf(new Subscriber("cometd-subscriber", cometdUri)).start + val cometdPublisher = actorOf(new Publisher("cometd-publisher", cometdUri)).start + + val cometdPublisherBridge = actorOf(new PublisherBridge("jetty:http://0.0.0.0:8877/camel/pub/cometd", cometdPublisher)).start + } + + +Quartz Scheduler Example +------------------------ + +Here is an example showing how simple is to implement a cron-style scheduler by +using the Camel Quartz component in Akka. + +The following example creates a "timer" actor which fires a message every 2 +seconds: + +.. code-block:: scala + + package com.dimingo.akka + + import akka.actor.Actor + import akka.actor.Actor.actorOf + + import akka.camel.{Consumer, Message} + import akka.camel.CamelServiceManager._ + + class MyQuartzActor extends Actor with Consumer { + + def endpointUri = "quartz://example?cron=0/2+*+*+*+*+?" + + def receive = { + + case msg => println("==============> received %s " format msg) + + } // end receive + + } // end MyQuartzActor + + object MyQuartzActor { + + def main(str: Array[String]) { + + // start the Camel service + startCamelService + + // create a quartz actor + val myActor = actorOf[MyQuartzActor] + + // start the quartz actor + myActor.start + + } // end main + + } // end MyQuartzActor + +The full working example is available for download here: +http://www.dimingo.com/akka/examples/example-akka-quartz.tar.gz + +You can launch it using the maven command: + +.. code-block:: none + + $ mvn scala:run -DmainClass=com.dimingo.akka.MyQuartzActor + +For more information about the Camel Quartz component, see here: +http://camel.apache.org/quartz.html diff --git a/akka-docs/modules/microkernel.rst b/akka-docs/modules/microkernel.rst new file mode 100644 index 0000000000..17b6072d40 --- /dev/null +++ b/akka-docs/modules/microkernel.rst @@ -0,0 +1,53 @@ + +.. _microkernel: + +############# + Microkernel +############# + + +Download Akka Modules +===================== + +Download the full Akka Modules distribution from http://akka.io/downloads + + +Build latest version from source +================================ + +To build the latest version see :ref:`building-akka-modules`. + + +Run the microkernel +=================== + +To start the kernel use the scripts in the ``bin`` directory. + +All services are configured in the ``config/akka.conf`` configuration file. See +the Akka documentation on Configuration for more details. Services you want to +be started up automatically should be listed in the list of ``boot`` classes in +the configuration. + +Put your application in the ``deploy`` directory. + + +Akka Home +--------- + +Note that the microkernel needs to know where the Akka home is (the base +directory of the microkernel). The above scripts do this for you. Otherwise, you +can set Akka home by: + +* Specifying the ``AKKA_HOME`` environment variable + +* Specifying the ``-Dakka.home`` java option + + +.. _hello-microkernel: + +Hello Microkernel +================= + +There is a very simple Akka Mist sample project included in the microkernel +``deploy`` directory. Start the microkernel with the start script and then go to +http://localhost:9998 to say Hello to the microkernel. diff --git a/akka-docs/modules/spring.rst b/akka-docs/modules/spring.rst new file mode 100644 index 0000000000..29bf4632cf --- /dev/null +++ b/akka-docs/modules/spring.rst @@ -0,0 +1,335 @@ + +.. _spring-module: + +#################### + Spring Integration +#################### + +Module stability: **STABLE** + +Akkas integration with the `Spring Framework `_ supplies the Spring way of using the Typed Actor Java API and for CamelService configuration for :ref:`camel-spring-applications`. It uses Spring's custom namespaces to create Typed Actors, supervisor hierarchies and a CamelService in a Spring environment. + +Contents: + +.. contents:: :local: + +To use the custom name space tags for Akka you have to add the XML schema definition to your spring configuration. It is available at `http://akka.io/akka-1.0.xsd `_. The namespace for Akka is: + +.. code-block:: xml + + xmlns:akka="http://akka.io/schema/akka" + +Example header for Akka Spring configuration: + +.. code-block:: xml + + + + +- + +Actors +------ + +Actors in Java are created by extending the 'UntypedActor' class and implementing the 'onReceive' method. + +Example how to create Actors with the Spring framework: + +.. code-block:: xml + + + + + + +Supported scopes are singleton and prototype. Dependencies and properties are set with Springs ```` element. +A dependency can be either a ```` or a regular ````. + +Get the Actor from the Spring context: + +.. code-block:: java + + ApplicationContext context = new ClassPathXmlApplicationContext("akka-spring-config.xml"); + ActorRef actorRef = (ActorRef) context.getBean("myActor"); + +Typed Actors +------------ + +Here are some examples how to create Typed Actors with the Spring framework: + +Creating a Typed Actor: +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: xml + + + + + + + + +Supported scopes are singleton and prototype. Dependencies and properties are set with Springs ```` element. +A dependency can be either a ```` or a regular ````. + +Get the Typed Actor from the Spring context: + +.. code-block:: java + + ApplicationContext context = new ClassPathXmlApplicationContext("akka-spring-config.xml"); + MyPojo myPojo = (MyPojo) context.getBean("myActor"); + +Remote Actors +------------- + +For details on server managed and client managed remote actors see Remote Actor documentation. + +Configuration for a client managed remote Actor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + + + + +The default for 'managed-by' is "client", so in the above example it could be left out. + +Configuration for a server managed remote Actor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Server side +*********** + +:: + + + + + + + + + + +If the server specified by 'host' and 'port' does not exist it will not be registered. + +Client side +*********** + +:: + + + + + +Configuration for a client managed remote Typed Actor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: xml + + + + + +Configuration for a server managed remote Typed Actor +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sever side setup +**************** + +:: + + + + + +Client side setup +***************** + +:: + + + + +Dispatchers +----------- + +Configuration for a Typed Actor or Untyped Actor with a custom dispatcher +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you don't want to use the default dispatcher you can define your own dispatcher in the spring configuration. For more information on dispatchers have a look at Dispatchers documentation. + +.. code-block:: xml + + + + + + + + + + + +If you want to or have to share the dispatcher between Actors you can define a dispatcher and reference it from the Typed Actor configuration: + +.. code-block:: xml + + + + + + + + + +The following dispatcher types are available in spring configuration: + +* executor-based-event-driven +* executor-based-event-driven-work-stealing +* thread-based + +The following queue types are configurable for dispatchers using thread pools: + +* bounded-linked-blocking-queue +* unbounded-linked-blocking-queue +* synchronous-queue +* bounded-array-blocking-queue + +If you have set up your IDE to be XSD-aware you can easily write your configuration through auto-completion. + +Stopping Typed Actors and Untyped Actors +---------------------------------------- + +Actors with scope singleton are stopped when the application context is closed. Actors with scope prototype must be stopped by the application. + +Supervisor Hierarchies +---------------------- + +The supervisor configuration in Spring follows the declarative configuration for the Java API. Have a look at Akka's approach to fault tolerance. + +Example spring supervisor configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: xml + + + + + + + java.io.IOException + + + + + + + + + + + + + + java.io.IOException + java.lang.NullPointerException + + + + + + + + + + +Get the TypedActorConfigurator from the Spring context +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: java + + TypedActorConfigurator myConfigurator = (TypedActorConfigurator) context.getBean("my-supervisor"); + MyPojo myPojo = (MyPOJO) myConfigurator.getInstance(MyPojo.class); + +Property Placeholders +--------------------- + +The Akka configuration can be made available as property placeholders by using a custom property placeholder configurer for Configgy: + +:: + + + + + + + +Camel configuration +------------------- + +For details refer to the :ref:`camel-module` documentation: + +* CamelService configuration for :ref:`camel-spring-applications` +* Access to Typed Actors :ref:`camel-typed-actors-using-spring`