From 23dd957ba254e1070f526d7435b0a482351a6d34 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 15 Nov 2013 16:28:14 +0100 Subject: [PATCH] =doc #3689 Make activator templates for camel samples * @rkuhn found the problems in the scala camel samples - HttpSample returns scrambled data - CustomRouteSample times out --- akka-docs/rst/java/camel.rst | 120 ++----------- .../docs/camel/sample/http/HttpSample.java | 23 --- .../sample/route/CustomRouteBuilder.java | 18 -- .../camel/sample/route/CustomRouteSample.java | 23 --- .../docs/camel/sample/route/Producer1.java | 10 -- akka-docs/rst/scala/camel.rst | 113 ++---------- .../code/docs/camel/CustomRouteExample.scala | 53 ------ .../scala/code/docs/camel/HttpExample.scala | 52 ------ .../scala/code/docs/camel/QuartzExample.scala | 30 ---- .../akka-sample-camel-java/.gitignore | 17 ++ akka-samples/akka-sample-camel-java/LICENSE | 13 ++ .../activator.properties | 4 + akka-samples/akka-sample-camel-java/build.sbt | 14 ++ .../project/build.properties | 1 + .../java/sample/camel}/http/HttpConsumer.java | 8 +- .../java/sample/camel}/http/HttpProducer.java | 15 +- .../java/sample/camel/http/HttpSample.java | 15 ++ .../sample/camel}/http/HttpTransformer.java | 12 +- .../sample/camel}/quartz/MyQuartzActor.java | 10 +- .../sample/camel}/quartz/QuartzSample.java | 5 +- .../camel/route/CustomRouteBuilder.java | 15 ++ .../sample/camel/route/CustomRouteSample.java | 19 ++ .../sample/camel/route/RouteConsumer.java | 8 +- .../sample/camel/route/RouteProducer.java | 9 + .../sample/camel/route/RouteTransformer.java | 23 ++- .../tutorial}/camel-async-interact.png | Bin .../tutorial}/camel-async-sequence.png | Bin .../tutorial}/camel-custom-route.png | Bin .../tutorial/index.html | 163 ++++++++++++++++++ .../akka-sample-camel-scala/.gitignore | 17 ++ akka-samples/akka-sample-camel-scala/LICENSE | 13 ++ .../activator.properties | 4 + .../akka-sample-camel-scala/build.sbt | 14 ++ .../project/build.properties | 1 + .../sample/camel/CustomRouteExample.scala | 58 +++++++ .../main/scala/sample/camel/HttpExample.scala | 58 +++++++ .../scala/sample/camel/QuartzExample.scala | 26 +++ .../tutorial/camel-async-interact.png | Bin 0 -> 21857 bytes .../tutorial/camel-async-sequence.png | Bin 0 -> 7492 bytes .../tutorial/camel-custom-route.png | Bin 0 -> 21359 bytes .../tutorial/index.html | 161 +++++++++++++++++ akka-samples/akka-sample-camel/README.md | 15 -- .../main/scala/AsyncRouteAndTransform.scala | 49 ------ .../src/main/scala/SimpleFileConsumer.scala | 24 --- .../activator.properties | 2 +- .../activator.properties | 2 +- project/AkkaBuild.scala | 15 +- 47 files changed, 693 insertions(+), 559 deletions(-) delete mode 100644 akka-docs/rst/java/code/docs/camel/sample/http/HttpSample.java delete mode 100644 akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteBuilder.java delete mode 100644 akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteSample.java delete mode 100644 akka-docs/rst/java/code/docs/camel/sample/route/Producer1.java delete mode 100644 akka-docs/rst/scala/code/docs/camel/CustomRouteExample.scala delete mode 100644 akka-docs/rst/scala/code/docs/camel/HttpExample.scala delete mode 100644 akka-docs/rst/scala/code/docs/camel/QuartzExample.scala create mode 100644 akka-samples/akka-sample-camel-java/.gitignore create mode 100644 akka-samples/akka-sample-camel-java/LICENSE create mode 100644 akka-samples/akka-sample-camel-java/activator.properties create mode 100644 akka-samples/akka-sample-camel-java/build.sbt create mode 100644 akka-samples/akka-sample-camel-java/project/build.properties rename {akka-docs/rst/java/code/docs/camel/sample => akka-samples/akka-sample-camel-java/src/main/java/sample/camel}/http/HttpConsumer.java (66%) rename {akka-docs/rst/java/code/docs/camel/sample => akka-samples/akka-sample-camel-java/src/main/java/sample/camel}/http/HttpProducer.java (60%) create mode 100644 akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpSample.java rename {akka-docs/rst/java/code/docs/camel/sample => akka-samples/akka-sample-camel-java/src/main/java/sample/camel}/http/HttpTransformer.java (67%) rename {akka-docs/rst/java/code/docs/camel/sample => akka-samples/akka-sample-camel-java/src/main/java/sample/camel}/quartz/MyQuartzActor.java (66%) rename {akka-docs/rst/java/code/docs/camel/sample => akka-samples/akka-sample-camel-java/src/main/java/sample/camel}/quartz/QuartzSample.java (79%) create mode 100644 akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteBuilder.java create mode 100644 akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteSample.java rename akka-docs/rst/java/code/docs/camel/sample/route/Consumer3.java => akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteConsumer.java (79%) create mode 100644 akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteProducer.java rename akka-docs/rst/java/code/docs/camel/sample/route/Transformer.java => akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteTransformer.java (55%) rename {akka-docs/rst/images => akka-samples/akka-sample-camel-java/tutorial}/camel-async-interact.png (100%) rename {akka-docs/rst/images => akka-samples/akka-sample-camel-java/tutorial}/camel-async-sequence.png (100%) rename {akka-docs/rst/images => akka-samples/akka-sample-camel-java/tutorial}/camel-custom-route.png (100%) create mode 100644 akka-samples/akka-sample-camel-java/tutorial/index.html create mode 100644 akka-samples/akka-sample-camel-scala/.gitignore create mode 100644 akka-samples/akka-sample-camel-scala/LICENSE create mode 100644 akka-samples/akka-sample-camel-scala/activator.properties create mode 100644 akka-samples/akka-sample-camel-scala/build.sbt create mode 100644 akka-samples/akka-sample-camel-scala/project/build.properties create mode 100644 akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/CustomRouteExample.scala create mode 100644 akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/HttpExample.scala create mode 100644 akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/QuartzExample.scala create mode 100644 akka-samples/akka-sample-camel-scala/tutorial/camel-async-interact.png create mode 100644 akka-samples/akka-sample-camel-scala/tutorial/camel-async-sequence.png create mode 100644 akka-samples/akka-sample-camel-scala/tutorial/camel-custom-route.png create mode 100644 akka-samples/akka-sample-camel-scala/tutorial/index.html delete mode 100644 akka-samples/akka-sample-camel/README.md delete mode 100644 akka-samples/akka-sample-camel/src/main/scala/AsyncRouteAndTransform.scala delete mode 100644 akka-samples/akka-sample-camel/src/main/scala/SimpleFileConsumer.scala diff --git a/akka-docs/rst/java/camel.rst b/akka-docs/rst/java/camel.rst index 28fe70e6c2..7be0c5aad4 100644 --- a/akka-docs/rst/java/camel.rst +++ b/akka-docs/rst/java/camel.rst @@ -312,7 +312,7 @@ 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-java` that implements both, an asynchronous +also :ref:`camel-examples-java` that implements both, an asynchronous consumer and an asynchronous producer, with the jetty component. If the used Camel component is blocking it might be necessary to use a separate @@ -469,116 +469,18 @@ __ https://svn.apache.org/repos/asf/camel/tags/camel-2.8.0/camel-core/src/main/j Examples ======== -.. _camel-async-example-java: +The `Typesafe Activator `_ +tutorial named `Akka Camel Samples with Java `_ +contains 3 samples: -Asynchronous routing and transformation example ------------------------------------------------ + * Asynchronous routing and transformation - This example demonstrates how to implement consumer and + producer actors that support :ref:`camel-asynchronous-routing-java` with their Camel endpoints. + + * Custom Camel route - Demonstrates the combined usage of a ``Producer`` and a + ``Consumer`` actor as well as the inclusion of a custom Camel route. -This example demonstrates how to implement consumer and producer actors that -support :ref:`camel-asynchronous-routing-java` 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*. To run this example, add -a Boot class that starts the actors. After starting -the :ref:`microkernel-java`, 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 occurrences -of *Akka* with *AKKA*. The transformation result is sent back the HttpConsumer -which finally returns it to the browser. - -.. image:: ../images/camel-async-interact.png - -Implementing the example actor classes and wiring them together is rather easy -as shown in the following snippet. - -.. includecode:: code/docs/camel/sample/http/HttpConsumer.java#HttpExample -.. includecode:: code/docs/camel/sample/http/HttpProducer.java#HttpExample -.. includecode:: code/docs/camel/sample/http/HttpTransformer.java#HttpExample -.. includecode:: code/docs/camel/sample/http/HttpSample.java#HttpExample - -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:: ../images/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:: ../images/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 consumer, transformer and -producer actor implementations are as follows. - -.. includecode:: code/docs/camel/sample/route/Consumer3.java#CustomRouteExample -.. includecode:: code/docs/camel/sample/route/Transformer.java#CustomRouteExample -.. includecode:: code/docs/camel/sample/route/Producer1.java#CustomRouteExample -.. includecode:: code/docs/camel/sample/route/CustomRouteSample.java#CustomRouteExample - -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 done in the code above. - -To run the example, add the lines shown in the example to a Boot class and the start the :ref:`microkernel-java` 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 - - -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: - -.. includecode:: code/docs/camel/sample/quartz/MyQuartzActor.java#QuartzExample -.. includecode:: code/docs/camel/sample/quartz/QuartzSample.java#QuartzExample - -For more information about the Camel Quartz component, see here: -http://camel.apache.org/quartz.html + * Quartz Scheduler Example - Showing how simple is to implement a cron-style scheduler by + using the Camel Quartz component Additional Resources ==================== diff --git a/akka-docs/rst/java/code/docs/camel/sample/http/HttpSample.java b/akka-docs/rst/java/code/docs/camel/sample/http/HttpSample.java deleted file mode 100644 index 2143c33158..0000000000 --- a/akka-docs/rst/java/code/docs/camel/sample/http/HttpSample.java +++ /dev/null @@ -1,23 +0,0 @@ -package docs.camel.sample.http; - -import akka.actor.*; - -public class HttpSample { - public static void main(String[] args) { - //#HttpExample - // Create the actors. this can be done in a Boot class so you can - // run the example in the MicroKernel. Just add the three lines below - // to your boot class. - ActorSystem system = ActorSystem.create("some-system"); - - final ActorRef httpTransformer = system.actorOf( - Props.create(HttpTransformer.class)); - - final ActorRef httpProducer = system.actorOf( - Props.create(HttpProducer.class, httpTransformer)); - - final ActorRef httpConsumer = system.actorOf( - Props.create(HttpConsumer.class, httpProducer)); - //#HttpExample - } -} diff --git a/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteBuilder.java b/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteBuilder.java deleted file mode 100644 index ad68d38609..0000000000 --- a/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteBuilder.java +++ /dev/null @@ -1,18 +0,0 @@ -package docs.camel.sample.route; - -//#CustomRouteExample -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.apache.camel.builder.RouteBuilder; - -public class CustomRouteBuilder extends RouteBuilder{ - public void configure() throws Exception { - from("direct:welcome").process(new Processor(){ - public void process(Exchange exchange) throws Exception { - exchange.getOut().setBody(String.format("Welcome %s", - exchange.getIn().getBody())); - } - }); - } -} -//#CustomRouteExample diff --git a/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteSample.java b/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteSample.java deleted file mode 100644 index f4a3760542..0000000000 --- a/akka-docs/rst/java/code/docs/camel/sample/route/CustomRouteSample.java +++ /dev/null @@ -1,23 +0,0 @@ -package docs.camel.sample.route; - -import akka.actor.*; -import akka.camel.CamelExtension; - -public class CustomRouteSample { - @SuppressWarnings("unused") - public static void main(String[] args) { - try { - //#CustomRouteExample - // the below lines can be added to a Boot class, so that you can run the - // example from a MicroKernel - ActorSystem system = ActorSystem.create("some-system"); - final ActorRef producer = system.actorOf(Props.create(Producer1.class)); - final ActorRef mediator = system.actorOf(Props.create(Transformer.class, producer)); - final ActorRef consumer = system.actorOf(Props.create(Consumer3.class, mediator)); - CamelExtension.get(system).context().addRoutes(new CustomRouteBuilder()); - //#CustomRouteExample - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/akka-docs/rst/java/code/docs/camel/sample/route/Producer1.java b/akka-docs/rst/java/code/docs/camel/sample/route/Producer1.java deleted file mode 100644 index 4f937fc95f..0000000000 --- a/akka-docs/rst/java/code/docs/camel/sample/route/Producer1.java +++ /dev/null @@ -1,10 +0,0 @@ -package docs.camel.sample.route; -//#CustomRouteExample -import akka.camel.javaapi.UntypedProducerActor; - -public class Producer1 extends UntypedProducerActor{ - public String getEndpointUri() { - return "direct:welcome"; - } -} -//#CustomRouteExample diff --git a/akka-docs/rst/scala/camel.rst b/akka-docs/rst/scala/camel.rst index 5bce74953a..a3f94baf8b 100644 --- a/akka-docs/rst/scala/camel.rst +++ b/akka-docs/rst/scala/camel.rst @@ -308,7 +308,7 @@ 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 +also :ref:`camel-examples` that implements both, an asynchronous consumer and an asynchronous producer, with the jetty component. If the used Camel component is blocking it might be necessary to use a separate @@ -463,110 +463,19 @@ __ https://svn.apache.org/repos/asf/camel/tags/camel-2.8.0/camel-core/src/main/j Examples ======== -.. _camel-async-example: +The `Typesafe Activator `_ +tutorial named `Akka Camel Samples with Scala `_ +contains 3 samples: -Asynchronous routing and transformation example ------------------------------------------------ + * Asynchronous routing and transformation - This example demonstrates how to implement consumer and + producer actors that support :ref:`camel-asynchronous-routing` with their Camel endpoints. + + * Custom Camel route - Demonstrates the combined usage of a ``Producer`` and a + ``Consumer`` actor as well as the inclusion of a custom Camel route. -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*. To run this example, add -a Boot class that starts the actors. After starting -the :ref:`microkernel-scala`, 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. + * Quartz Scheduler Example - Showing how simple is to implement a cron-style scheduler by + using the Camel Quartz component -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 occurrences -of *Akka* with *AKKA*. The transformation result is sent back the HttpConsumer -which finally returns it to the browser. - -.. image:: ../images/camel-async-interact.png - -Implementing the example actor classes and wiring them together is rather easy -as shown in the following snippet. - -.. includecode:: code/docs/camel/HttpExample.scala#HttpExample - -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:: ../images/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:: ../images/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 consumer, transformer and -producer actor implementations are as follows. - -.. includecode:: code/docs/camel/CustomRouteExample.scala#CustomRouteExample - - -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 done in the code above. - -To run the example, add the lines shown in the example to a Boot class and the start the :ref:`microkernel-scala` 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 - - -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: - -.. includecode:: code/docs/camel/QuartzExample.scala#Quartz - -For more information about the Camel Quartz component, see here: -http://camel.apache.org/quartz.html Additional Resources ==================== diff --git a/akka-docs/rst/scala/code/docs/camel/CustomRouteExample.scala b/akka-docs/rst/scala/code/docs/camel/CustomRouteExample.scala deleted file mode 100644 index 49cac853c5..0000000000 --- a/akka-docs/rst/scala/code/docs/camel/CustomRouteExample.scala +++ /dev/null @@ -1,53 +0,0 @@ -package docs.camel - -object CustomRouteExample { - { - //#CustomRouteExample - import akka.actor.{ Actor, ActorRef, Props, ActorSystem } - import akka.camel.{ CamelMessage, Consumer, Producer, CamelExtension } - import org.apache.camel.builder.RouteBuilder - import org.apache.camel.{ Exchange, Processor } - - 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: CamelMessage ⇒ transformer.forward(msg.bodyAs[String]) - } - } - - class Transformer(producer: ActorRef) extends Actor { - def receive = { - // example: transform message body "foo" to "- foo -" and forward result - // to producer - case msg: CamelMessage ⇒ - producer.forward(msg.mapBody((body: String) ⇒ "- %s -" format body)) - } - } - - class Producer1 extends Actor with Producer { - def endpointUri = "direct:welcome" - } - - 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) - } - }) - } - } - // the below lines can be added to a Boot class, so that you can run the - // example from a MicroKernel - val system = ActorSystem("some-system") - val producer = system.actorOf(Props[Producer1]) - val mediator = system.actorOf(Props(classOf[Transformer], producer)) - val consumer = system.actorOf(Props(classOf[Consumer3], mediator)) - CamelExtension(system).context.addRoutes(new CustomRouteBuilder) - //#CustomRouteExample - } - -} diff --git a/akka-docs/rst/scala/code/docs/camel/HttpExample.scala b/akka-docs/rst/scala/code/docs/camel/HttpExample.scala deleted file mode 100644 index a2fd16944b..0000000000 --- a/akka-docs/rst/scala/code/docs/camel/HttpExample.scala +++ /dev/null @@ -1,52 +0,0 @@ -package docs.camel - -object HttpExample { - - { - //#HttpExample - import org.apache.camel.Exchange - import akka.actor.{ Actor, ActorRef, Props, ActorSystem } - import akka.camel.{ Producer, CamelMessage, Consumer } - import akka.actor.Status.Failure - - class HttpConsumer(producer: ActorRef) extends Consumer { - def endpointUri = "jetty:http://0.0.0.0:8875/" - - def receive = { - case msg ⇒ producer forward msg - } - } - - class HttpProducer(transformer: ActorRef) extends Actor with Producer { - def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" - - override def transformOutgoingMessage(msg: Any) = msg match { - case msg: CamelMessage ⇒ msg.copy(headers = msg.headers ++ - msg.headers(Set(Exchange.HTTP_PATH))) - } - - override def routeResponse(msg: Any) { transformer forward msg } - } - - class HttpTransformer extends Actor { - def receive = { - case msg: CamelMessage ⇒ - sender ! (msg.mapBody { body: Array[Byte] ⇒ - new String(body).replaceAll("Akka ", "AKKA ") - }) - case msg: Failure ⇒ sender ! msg - } - } - - // Create the actors. this can be done in a Boot class so you can - // run the example in the MicroKernel. Just add the three lines below - // to your boot class. - val system = ActorSystem("some-system") - val httpTransformer = system.actorOf(Props[HttpTransformer]) - val httpProducer = system.actorOf(Props(classOf[HttpProducer], httpTransformer)) - val httpConsumer = system.actorOf(Props(classOf[HttpConsumer], httpProducer)) - //#HttpExample - - } - -} diff --git a/akka-docs/rst/scala/code/docs/camel/QuartzExample.scala b/akka-docs/rst/scala/code/docs/camel/QuartzExample.scala deleted file mode 100644 index f0ad04be57..0000000000 --- a/akka-docs/rst/scala/code/docs/camel/QuartzExample.scala +++ /dev/null @@ -1,30 +0,0 @@ -package docs.camel - -object QuartzExample { - //#Quartz - import akka.actor.{ ActorSystem, Props } - - import akka.camel.{ Consumer } - - class MyQuartzActor extends 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]) { - val system = ActorSystem("my-quartz-system") - system.actorOf(Props[MyQuartzActor]) - } // end main - - } // end MyQuartzActor - //#Quartz -} diff --git a/akka-samples/akka-sample-camel-java/.gitignore b/akka-samples/akka-sample-camel-java/.gitignore new file mode 100644 index 0000000000..660c959e44 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/.gitignore @@ -0,0 +1,17 @@ +*# +*.iml +*.ipr +*.iws +*.pyc +*.tm.epoch +*.vim +*-shim.sbt +.idea/ +/project/plugins/project +project/boot +target/ +/logs +.cache +.classpath +.project +.settings \ No newline at end of file diff --git a/akka-samples/akka-sample-camel-java/LICENSE b/akka-samples/akka-sample-camel-java/LICENSE new file mode 100644 index 0000000000..a02154466b --- /dev/null +++ b/akka-samples/akka-sample-camel-java/LICENSE @@ -0,0 +1,13 @@ +Copyright 2013 Typesafe, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/akka-samples/akka-sample-camel-java/activator.properties b/akka-samples/akka-sample-camel-java/activator.properties new file mode 100644 index 0000000000..427d9683d4 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/activator.properties @@ -0,0 +1,4 @@ +name=akka-sample-camel-java +title=Akka Camel Samples with Java +description=Akka Camel Samples with Java +tags=akka,camel,java,sample diff --git a/akka-samples/akka-sample-camel-java/build.sbt b/akka-samples/akka-sample-camel-java/build.sbt new file mode 100644 index 0000000000..288934017e --- /dev/null +++ b/akka-samples/akka-sample-camel-java/build.sbt @@ -0,0 +1,14 @@ +name := "akka-sample-camel-java" + +version := "1.0" + +scalaVersion := "2.10.3" + +libraryDependencies ++= Seq( + "com.typesafe.akka" %% "akka-camel" % "2.3-SNAPSHOT", + "org.apache.camel" % "camel-jetty" % "2.10.3", + "org.apache.camel" % "camel-quartz" % "2.10.3", + "org.slf4j" % "slf4j-api" % "1.7.2", + "ch.qos.logback" % "logback-classic" % "1.0.7" +) + diff --git a/akka-samples/akka-sample-camel-java/project/build.properties b/akka-samples/akka-sample-camel-java/project/build.properties new file mode 100644 index 0000000000..0974fce44d --- /dev/null +++ b/akka-samples/akka-sample-camel-java/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.0 diff --git a/akka-docs/rst/java/code/docs/camel/sample/http/HttpConsumer.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpConsumer.java similarity index 66% rename from akka-docs/rst/java/code/docs/camel/sample/http/HttpConsumer.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpConsumer.java index 9ca5fbb886..34e373cecd 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/http/HttpConsumer.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpConsumer.java @@ -1,14 +1,13 @@ -package docs.camel.sample.http; +package sample.camel.http; import akka.actor.ActorRef; import akka.camel.javaapi.UntypedConsumerActor; -//#HttpExample -public class HttpConsumer extends UntypedConsumerActor{ +public class HttpConsumer extends UntypedConsumerActor { private ActorRef producer; - public HttpConsumer(ActorRef producer){ + public HttpConsumer(ActorRef producer) { this.producer = producer; } @@ -20,4 +19,3 @@ public class HttpConsumer extends UntypedConsumerActor{ producer.forward(message, getContext()); } } -//#HttpExample \ No newline at end of file diff --git a/akka-docs/rst/java/code/docs/camel/sample/http/HttpProducer.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpProducer.java similarity index 60% rename from akka-docs/rst/java/code/docs/camel/sample/http/HttpProducer.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpProducer.java index 27e0cb0df3..8c37b50c4d 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/http/HttpProducer.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpProducer.java @@ -1,4 +1,4 @@ -package docs.camel.sample.http; +package sample.camel.http; import akka.actor.ActorRef; import akka.camel.CamelMessage; @@ -8,8 +8,7 @@ import org.apache.camel.Exchange; import java.util.HashSet; import java.util.Set; -//#HttpExample -public class HttpProducer extends UntypedProducerActor{ +public class HttpProducer extends UntypedProducerActor { private ActorRef transformer; public HttpProducer(ActorRef transformer) { @@ -17,9 +16,13 @@ public class HttpProducer extends UntypedProducerActor{ } public String getEndpointUri() { + // bridgeEndpoint=true makes the producer ignore the Exchange.HTTP_URI header, + // and use the endpoint's URI for request return "jetty://http://akka.io/?bridgeEndpoint=true"; } + // before producing messages to endpoints, producer actors can pre-process + // them by overriding the onTransformOutgoingMessage method @Override public Object onTransformOutgoingMessage(Object message) { if (message instanceof CamelMessage) { @@ -27,12 +30,14 @@ public class HttpProducer extends UntypedProducerActor{ Set httpPath = new HashSet(); httpPath.add(Exchange.HTTP_PATH); return camelMessage.withHeaders(camelMessage.getHeaders(httpPath)); - } else return super.onTransformOutgoingMessage(message); + } else + return super.onTransformOutgoingMessage(message); } + // instead of replying to the initial sender, producer actors can implement custom + // response processing by overriding the onRouteResponse method @Override public void onRouteResponse(Object message) { transformer.forward(message, getContext()); } } -//#HttpExample \ No newline at end of file diff --git a/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpSample.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpSample.java new file mode 100644 index 0000000000..19c1eef98f --- /dev/null +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpSample.java @@ -0,0 +1,15 @@ +package sample.camel.http; + +import akka.actor.*; + +public class HttpSample { + public static void main(String[] args) { + ActorSystem system = ActorSystem.create("some-system"); + + final ActorRef httpTransformer = system.actorOf(Props.create(HttpTransformer.class)); + + final ActorRef httpProducer = system.actorOf(Props.create(HttpProducer.class, httpTransformer)); + + final ActorRef httpConsumer = system.actorOf(Props.create(HttpConsumer.class, httpProducer)); + } +} diff --git a/akka-docs/rst/java/code/docs/camel/sample/http/HttpTransformer.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpTransformer.java similarity index 67% rename from akka-docs/rst/java/code/docs/camel/sample/http/HttpTransformer.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpTransformer.java index 7aee59293a..6ae1e2bfcc 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/http/HttpTransformer.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/http/HttpTransformer.java @@ -1,21 +1,18 @@ -package docs.camel.sample.http; +package sample.camel.http; import akka.actor.Status; import akka.actor.UntypedActor; import akka.camel.CamelMessage; import akka.dispatch.Mapper; -import akka.japi.Function; -//#HttpExample -public class HttpTransformer extends UntypedActor{ +public class HttpTransformer extends UntypedActor { public void onReceive(Object message) { if (message instanceof CamelMessage) { CamelMessage camelMessage = (CamelMessage) message; - CamelMessage replacedMessage = - camelMessage.mapBody(new Mapper(){ + CamelMessage replacedMessage = camelMessage.mapBody(new Mapper() { @Override public String apply(Object body) { - String text = new String((byte[])body); + String text = new String((byte[]) body); return text.replaceAll("Akka ", "AKKA "); } }); @@ -26,4 +23,3 @@ public class HttpTransformer extends UntypedActor{ unhandled(message); } } -//#HttpExample \ No newline at end of file diff --git a/akka-docs/rst/java/code/docs/camel/sample/quartz/MyQuartzActor.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/MyQuartzActor.java similarity index 66% rename from akka-docs/rst/java/code/docs/camel/sample/quartz/MyQuartzActor.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/MyQuartzActor.java index 7f38d01943..967abea0c8 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/quartz/MyQuartzActor.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/MyQuartzActor.java @@ -1,9 +1,9 @@ -package docs.camel.sample.quartz; -//#QuartzExample +package sample.camel.quartz; + import akka.camel.CamelMessage; import akka.camel.javaapi.UntypedConsumerActor; -public class MyQuartzActor extends UntypedConsumerActor{ +public class MyQuartzActor extends UntypedConsumerActor { public String getEndpointUri() { return "quartz://example?cron=0/2+*+*+*+*+?"; } @@ -11,10 +11,8 @@ public class MyQuartzActor extends UntypedConsumerActor{ public void onReceive(Object message) { if (message instanceof CamelMessage) { CamelMessage camelMessage = (CamelMessage) message; - String body = camelMessage.getBodyAs(String.class, getCamelContext()); - System.out.println(String.format("==============> received %s ", body)); + System.out.println(String.format("==============> received %s ", camelMessage)); } else unhandled(message); } } -//#QuartzExample \ No newline at end of file diff --git a/akka-docs/rst/java/code/docs/camel/sample/quartz/QuartzSample.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/QuartzSample.java similarity index 79% rename from akka-docs/rst/java/code/docs/camel/sample/quartz/QuartzSample.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/QuartzSample.java index 59875e77a6..2f4c73d38a 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/quartz/QuartzSample.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/quartz/QuartzSample.java @@ -1,5 +1,5 @@ -package docs.camel.sample.quartz; -//#QuartzExample +package sample.camel.quartz; + import akka.actor.ActorSystem; import akka.actor.Props; @@ -9,4 +9,3 @@ public class QuartzSample { system.actorOf(Props.create(MyQuartzActor.class)); } } -//#QuartzExample \ No newline at end of file diff --git a/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteBuilder.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteBuilder.java new file mode 100644 index 0000000000..97ace488e5 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteBuilder.java @@ -0,0 +1,15 @@ +package sample.camel.route; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; + +public class CustomRouteBuilder extends RouteBuilder { + public void configure() throws Exception { + from("direct:welcome").process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getOut().setBody(String.format("Welcome %s", exchange.getIn().getBody())); + } + }); + } +} diff --git a/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteSample.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteSample.java new file mode 100644 index 0000000000..669800b9f6 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/CustomRouteSample.java @@ -0,0 +1,19 @@ +package sample.camel.route; + +import akka.actor.*; +import akka.camel.CamelExtension; + +public class CustomRouteSample { + @SuppressWarnings("unused") + public static void main(String[] args) { + try { + ActorSystem system = ActorSystem.create("some-system"); + final ActorRef producer = system.actorOf(Props.create(RouteProducer.class)); + final ActorRef mediator = system.actorOf(Props.create(RouteTransformer.class, producer)); + final ActorRef consumer = system.actorOf(Props.create(RouteConsumer.class, mediator)); + CamelExtension.get(system).context().addRoutes(new CustomRouteBuilder()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/akka-docs/rst/java/code/docs/camel/sample/route/Consumer3.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteConsumer.java similarity index 79% rename from akka-docs/rst/java/code/docs/camel/sample/route/Consumer3.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteConsumer.java index 05cd7eb85a..d3067fd8ef 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/route/Consumer3.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteConsumer.java @@ -1,14 +1,13 @@ -package docs.camel.sample.route; +package sample.camel.route; -//#CustomRouteExample import akka.actor.ActorRef; import akka.camel.CamelMessage; import akka.camel.javaapi.UntypedConsumerActor; -public class Consumer3 extends UntypedConsumerActor{ +public class RouteConsumer extends UntypedConsumerActor { private ActorRef transformer; - public Consumer3(ActorRef transformer){ + public RouteConsumer(ActorRef transformer) { this.transformer = transformer; } @@ -26,4 +25,3 @@ public class Consumer3 extends UntypedConsumerActor{ unhandled(message); } } -//#CustomRouteExample diff --git a/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteProducer.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteProducer.java new file mode 100644 index 0000000000..5a47947087 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteProducer.java @@ -0,0 +1,9 @@ +package sample.camel.route; + +import akka.camel.javaapi.UntypedProducerActor; + +public class RouteProducer extends UntypedProducerActor { + public String getEndpointUri() { + return "direct:welcome"; + } +} diff --git a/akka-docs/rst/java/code/docs/camel/sample/route/Transformer.java b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteTransformer.java similarity index 55% rename from akka-docs/rst/java/code/docs/camel/sample/route/Transformer.java rename to akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteTransformer.java index 97cc8b8f09..5d0ff079c7 100644 --- a/akka-docs/rst/java/code/docs/camel/sample/route/Transformer.java +++ b/akka-samples/akka-sample-camel-java/src/main/java/sample/camel/route/RouteTransformer.java @@ -1,15 +1,14 @@ -package docs.camel.sample.route; -//#CustomRouteExample +package sample.camel.route; + import akka.actor.ActorRef; import akka.actor.UntypedActor; import akka.camel.CamelMessage; import akka.dispatch.Mapper; -import akka.japi.Function; -public class Transformer extends UntypedActor { +public class RouteTransformer extends UntypedActor { private ActorRef producer; - public Transformer(ActorRef producer) { + public RouteTransformer(ActorRef producer) { this.producer = producer; } @@ -18,16 +17,14 @@ public class Transformer extends UntypedActor { // example: transform message body "foo" to "- foo -" and forward result // to producer CamelMessage camelMessage = (CamelMessage) message; - CamelMessage transformedMessage = - camelMessage.mapBody(new Mapper(){ - @Override - public String apply(String body) { - return String.format("- %s -",body); - } - }); + CamelMessage transformedMessage = camelMessage.mapBody(new Mapper() { + @Override + public String apply(String body) { + return String.format("- %s -", body); + } + }); producer.forward(transformedMessage, getContext()); } else unhandled(message); } } -//#CustomRouteExample \ No newline at end of file diff --git a/akka-docs/rst/images/camel-async-interact.png b/akka-samples/akka-sample-camel-java/tutorial/camel-async-interact.png similarity index 100% rename from akka-docs/rst/images/camel-async-interact.png rename to akka-samples/akka-sample-camel-java/tutorial/camel-async-interact.png diff --git a/akka-docs/rst/images/camel-async-sequence.png b/akka-samples/akka-sample-camel-java/tutorial/camel-async-sequence.png similarity index 100% rename from akka-docs/rst/images/camel-async-sequence.png rename to akka-samples/akka-sample-camel-java/tutorial/camel-async-sequence.png diff --git a/akka-docs/rst/images/camel-custom-route.png b/akka-samples/akka-sample-camel-java/tutorial/camel-custom-route.png similarity index 100% rename from akka-docs/rst/images/camel-custom-route.png rename to akka-samples/akka-sample-camel-java/tutorial/camel-custom-route.png diff --git a/akka-samples/akka-sample-camel-java/tutorial/index.html b/akka-samples/akka-sample-camel-java/tutorial/index.html new file mode 100644 index 0000000000..9751aa9615 --- /dev/null +++ b/akka-samples/akka-sample-camel-java/tutorial/index.html @@ -0,0 +1,163 @@ + + + Akka Camel Samples with Java + + + + +
+

+This tutorial contains 3 samples of +Akka Camel. +

+ +
    +
  • Asynchronous routing and transformation
  • +
  • Custom Camel route
  • +
  • Quartz scheduler
  • +
+ +
+ +
+ +

Asynchronous routing and transformation

+ +

+This example demonstrates how to implement consumer and producer actors that +support + +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*. +

+ +

+To run this example, go to the Run +tab, and start the application main class sample.camel.http.HttpExample if it's not already started. +Then 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 HttpConsumeractor forwards the requests to the +HttpProducer.java +actor which retrieves the Akka homepage from http://akka.io. The retrieved HTML +is then forwarded to the +HttpTransformer.java +actor which replaces all occurrences of *Akka* with *AKKA*. The transformation result is sent back the HttpConsumer +which finally returns it to the browser. +

+ + + +

+Implementing the example actor classes and wiring them together is rather easy +as shown in HttpConsumer.java, +HttpProducer.java and +HttpTransformer.java. +

+ + +

+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. +

+ + + +
+
+ +

Custom Camel route example

+ +

+This section also demonstrates the combined usage of a +RouteProducer and a +RouteConsumer +actor as well as the inclusion of a +custom Camel route. +The following figure gives an overview. +

+ + + +
    +
  • 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 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 done in the code above. +

+ +

+To run this example, go to the Run +tab, and start the application main class sample.camel.route.CustomRouteExample +

+ +

+POST a message to http://localhost:8877/camel/welcome. +

+ +

+   curl -H "Content-Type: text/plain" -d "Anke" http://localhost:8877/camel/welcome
+
+ +

+The response should be: +

+ +

+   Welcome - Anke -
+
+ +
+
+ +

Quartz Scheduler Example

+ +

+Here is an example showing how simple it is to implement a cron-style scheduler by +using the Camel Quartz component in Akka. +

+

+Open MyQuartzActor.java. +

+

+The example creates a "timer" actor which fires a message every 2 +seconds. +

+ +

+For more information about the Camel Quartz component, see here: +http://camel.apache.org/quartz.html +

+ +
+ + + diff --git a/akka-samples/akka-sample-camel-scala/.gitignore b/akka-samples/akka-sample-camel-scala/.gitignore new file mode 100644 index 0000000000..660c959e44 --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/.gitignore @@ -0,0 +1,17 @@ +*# +*.iml +*.ipr +*.iws +*.pyc +*.tm.epoch +*.vim +*-shim.sbt +.idea/ +/project/plugins/project +project/boot +target/ +/logs +.cache +.classpath +.project +.settings \ No newline at end of file diff --git a/akka-samples/akka-sample-camel-scala/LICENSE b/akka-samples/akka-sample-camel-scala/LICENSE new file mode 100644 index 0000000000..a02154466b --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/LICENSE @@ -0,0 +1,13 @@ +Copyright 2013 Typesafe, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/akka-samples/akka-sample-camel-scala/activator.properties b/akka-samples/akka-sample-camel-scala/activator.properties new file mode 100644 index 0000000000..be391d3dce --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/activator.properties @@ -0,0 +1,4 @@ +name=akka-sample-camel-scala +title=Akka Camel Samples with Scala +description=Akka Camel Samples with Scala +tags=akka,camel,scala,sample diff --git a/akka-samples/akka-sample-camel-scala/build.sbt b/akka-samples/akka-sample-camel-scala/build.sbt new file mode 100644 index 0000000000..161a8588ee --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/build.sbt @@ -0,0 +1,14 @@ +name := "akka-sample-camel-scala" + +version := "1.0" + +scalaVersion := "2.10.3" + +libraryDependencies ++= Seq( + "com.typesafe.akka" %% "akka-camel" % "2.3-SNAPSHOT", + "org.apache.camel" % "camel-jetty" % "2.10.3", + "org.apache.camel" % "camel-quartz" % "2.10.3", + "org.slf4j" % "slf4j-api" % "1.7.2", + "ch.qos.logback" % "logback-classic" % "1.0.7" +) + diff --git a/akka-samples/akka-sample-camel-scala/project/build.properties b/akka-samples/akka-sample-camel-scala/project/build.properties new file mode 100644 index 0000000000..0974fce44d --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.0 diff --git a/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/CustomRouteExample.scala b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/CustomRouteExample.scala new file mode 100644 index 0000000000..c606f7832f --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/CustomRouteExample.scala @@ -0,0 +1,58 @@ +package sample.camel + +import org.apache.camel.Exchange +import org.apache.camel.Processor +import org.apache.camel.builder.RouteBuilder +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props +import akka.camel.CamelExtension +import akka.camel.CamelMessage +import akka.camel.Consumer +import akka.camel.Producer + +object CustomRouteExample { + + def main(args: Array[String]): Unit = { + val system = ActorSystem("some-system") + val producer = system.actorOf(Props[RouteProducer]) + val mediator = system.actorOf(Props(classOf[RouteTransformer], producer)) + val consumer = system.actorOf(Props(classOf[RouteConsumer], mediator)) + CamelExtension(system).context.addRoutes(new CustomRouteBuilder) + } + + class RouteConsumer(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: CamelMessage => transformer.forward(msg.withBodyAs[String]) + } + } + + class RouteTransformer(producer: ActorRef) extends Actor { + def receive = { + // example: transform message body "foo" to "- foo -" and forward result + // to producer + case msg: CamelMessage => + producer.forward(msg.mapBody((body: String) => "- %s -" format body)) + } + } + + class RouteProducer extends Actor with Producer { + def endpointUri = "direct:welcome" + } + + 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) + } + }) + } + } + +} diff --git a/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/HttpExample.scala b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/HttpExample.scala new file mode 100644 index 0000000000..f2ced742b5 --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/HttpExample.scala @@ -0,0 +1,58 @@ +package sample.camel + +import org.apache.camel.Exchange +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.ActorSystem +import akka.actor.Props +import akka.actor.Status.Failure +import akka.actor.actorRef2Scala +import akka.camel.CamelMessage +import akka.camel.Consumer +import akka.camel.Producer + +object HttpExample { + + def main(args: Array[String]): Unit = { + val system = ActorSystem("some-system") + val httpTransformer = system.actorOf(Props[HttpTransformer]) + val httpProducer = system.actorOf(Props(classOf[HttpProducer], httpTransformer)) + val httpConsumer = system.actorOf(Props(classOf[HttpConsumer], httpProducer)) + } + + class HttpConsumer(producer: ActorRef) extends Consumer { + def endpointUri = "jetty:http://0.0.0.0:8875/" + + def receive = { + case msg => producer forward msg + } + } + + class HttpProducer(transformer: ActorRef) extends Actor with Producer { + // bridgeEndpoint=true makes the producer ignore the Exchange.HTTP_URI header, + // and use the endpoint's URI for request + def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" + + // before producing messages to endpoints, producer actors can pre-process + // them by overriding the transformOutgoingMessage method + override def transformOutgoingMessage(msg: Any) = msg match { + case camelMsg: CamelMessage => camelMsg.copy(headers = + camelMsg.headers(Set(Exchange.HTTP_PATH))) + } + + // instead of replying to the initial sender, producer actors can implement custom + // response processing by overriding the routeResponse method + override def routeResponse(msg: Any) { transformer forward msg } + } + + class HttpTransformer extends Actor { + def receive = { + case msg: CamelMessage => + sender ! (msg.mapBody { body: Array[Byte] => + new String(body).replaceAll("Akka ", "AKKA ") + }) + case msg: Failure => sender ! msg + } + } + +} diff --git a/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/QuartzExample.scala b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/QuartzExample.scala new file mode 100644 index 0000000000..3a02a5be08 --- /dev/null +++ b/akka-samples/akka-sample-camel-scala/src/main/scala/sample/camel/QuartzExample.scala @@ -0,0 +1,26 @@ +package sample.camel + +import akka.actor.ActorSystem +import akka.actor.Props +import akka.camel.Consumer + +object QuartzExample { + + def main(args: Array[String]): Unit = { + val system = ActorSystem("my-quartz-system") + system.actorOf(Props[MyQuartzActor]) + } + + class MyQuartzActor extends Consumer { + + def endpointUri = "quartz://example?cron=0/2+*+*+*+*+?" + + def receive = { + + case msg => println("==============> received %s " format msg) + + } + + } + +} diff --git a/akka-samples/akka-sample-camel-scala/tutorial/camel-async-interact.png b/akka-samples/akka-sample-camel-scala/tutorial/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-samples/akka-sample-camel-scala/tutorial/camel-async-sequence.png b/akka-samples/akka-sample-camel-scala/tutorial/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-samples/akka-sample-camel-scala/tutorial/camel-custom-route.png b/akka-samples/akka-sample-camel-scala/tutorial/camel-custom-route.png new file mode 100644 index 0000000000000000000000000000000000000000..efacdb8f8296678cdd3465985090a1fd9419f19a GIT binary patch literal 21359 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 --> + + Akka Camel Samples with Scala + + + + +
+

+This tutorial contains 3 samples of +Akka Camel. +

+ +
    +
  • Asynchronous routing and transformation
  • +
  • Custom Camel route
  • +
  • Quartz scheduler
  • +
+ +
+ +
+ +

Asynchronous routing and transformation

+ +

+This example demonstrates how to implement consumer and producer actors that +support + +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*. +

+ +

+To run this example, go to the Run +tab, and start the application main class sample.camel.HttpExample if it's not already started. +Then 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 occurrences of *Akka* with *AKKA*. The transformation result is sent back the HttpConsumer +which finally returns it to the browser. +

+ + + +

+Implementing the example actor classes and wiring them together is rather easy +as shown in HttpExample.scala. +

+ + +

+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. +

+ + + +
+
+ +

Custom Camel route example

+ +

+This section also demonstrates the combined usage of a +RouteProducer +and a RouteConsumer +actor as well as the inclusion of a +custom Camel route. +The following figure gives an overview. +

+ + + +
    +
  • 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 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 done in the code above. +

+ +

+To run this example, go to the Run +tab, and start the application main class sample.camel.CustomRouteExample +

+ +

+POST a message to http://localhost:8877/camel/welcome. +

+ +

+   curl -H "Content-Type: text/plain" -d "Anke" http://localhost:8877/camel/welcome
+
+ +

+The response should be: +

+ +

+   Welcome - Anke -
+
+ +
+
+ +

Quartz Scheduler Example

+ +

+Here is an example showing how simple it is to implement a cron-style scheduler by +using the Camel Quartz component in Akka. +

+

+Open QuartzExample.scala. +

+

+The example creates a "timer" actor which fires a message every 2 +seconds. +

+ +

+For more information about the Camel Quartz component, see here: +http://camel.apache.org/quartz.html +

+ +
+ + + diff --git a/akka-samples/akka-sample-camel/README.md b/akka-samples/akka-sample-camel/README.md deleted file mode 100644 index d71806b0f9..0000000000 --- a/akka-samples/akka-sample-camel/README.md +++ /dev/null @@ -1,15 +0,0 @@ -Camel Sample -============ - -This sample is meant to be used by studying the code; it does not perform any -astounding functions when running it. If you want to run it, check out the akka -sources on your local hard drive, follow the [instructions for setting up Akka -with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html). -When you start SBT within the checked-out akka source directory, you can run -this sample by typing - - akka-sample-camel/run - -and then choose which of the demonstrations you would like to run. - -You can read more in the [Akka docs](http://akka.io/docs). diff --git a/akka-samples/akka-sample-camel/src/main/scala/AsyncRouteAndTransform.scala b/akka-samples/akka-sample-camel/src/main/scala/AsyncRouteAndTransform.scala deleted file mode 100644 index 85dff9f064..0000000000 --- a/akka-samples/akka-sample-camel/src/main/scala/AsyncRouteAndTransform.scala +++ /dev/null @@ -1,49 +0,0 @@ -import akka.actor.Status.Failure -import akka.actor.{ Actor, ActorRef, Props, ActorSystem } -import akka.camel.{ Producer, CamelMessage, Consumer } -import org.apache.camel.{ Exchange } - -/** - * Asynchronous routing and transformation example - */ -object AsyncRouteAndTransform extends App { - val system = ActorSystem("rewriteAkkaToAKKA") - val httpTransformer = system.actorOf(Props[HttpTransformer], "transformer") - val httpProducer = system.actorOf(Props(classOf[HttpProducer], httpTransformer), "producer") - val httpConsumer = system.actorOf(Props(classOf[HttpConsumer], httpProducer), "consumer") -} - -class HttpConsumer(producer: ActorRef) extends Consumer { - def endpointUri = "jetty:http://0.0.0.0:8875/" - def receive = { - case msg ⇒ producer forward msg - } -} - -class HttpProducer(transformer: ActorRef) extends Actor with Producer { - def endpointUri = "jetty://http://akka.io/?bridgeEndpoint=true" - - override def transformOutgoingMessage(msg: Any) = msg match { - case msg: CamelMessage ⇒ msg.copy(headers = msg.headers(Set(Exchange.HTTP_PATH))) - } - - override def routeResponse(msg: Any) { - transformer forward msg - } -} - -class HttpTransformer extends Actor { - def receive = { - case msg: CamelMessage ⇒ - val transformedMsg = msg.mapBody { - (body: Array[Byte]) ⇒ - new String(body).replaceAll("Akka", "AKKA") - // just to make the result look a bit better. - .replaceAll("href=\"/resources", "href=\"http://akka.io/resources") - .replaceAll("src=\"/resources", "src=\"http://akka.io/resources") - } - sender ! transformedMsg - case msg: Failure ⇒ sender ! msg - } -} - diff --git a/akka-samples/akka-sample-camel/src/main/scala/SimpleFileConsumer.scala b/akka-samples/akka-sample-camel/src/main/scala/SimpleFileConsumer.scala deleted file mode 100644 index 5b96afed2c..0000000000 --- a/akka-samples/akka-sample-camel/src/main/scala/SimpleFileConsumer.scala +++ /dev/null @@ -1,24 +0,0 @@ -import akka.actor.{ Props, ActorSystem } -import akka.camel.{ CamelMessage, Consumer } -import java.io.File -import org.apache.camel.Exchange - -object SimpleFileConsumer extends App { - val subDir = "consume-files" - val tmpDir = System.getProperty("java.io.tmpdir") - val consumeDir = new File(tmpDir, subDir) - consumeDir.mkdirs() - val tmpDirUri = "file://%s/%s" format (tmpDir, subDir) - - val system = ActorSystem("consume-files") - val fileConsumer = system.actorOf(Props(classOf[FileConsumer], tmpDirUri), "fileConsumer") - println(String.format("Put a text file in '%s', the consumer will pick it up!", consumeDir)) -} - -class FileConsumer(uri: String) extends Consumer { - def endpointUri = uri - def receive = { - case msg: CamelMessage ⇒ - println("Received file %s with content:\n%s".format(msg.headers(Exchange.FILE_NAME), msg.bodyAs[String])) - } -} diff --git a/akka-samples/akka-sample-main-java/activator.properties b/akka-samples/akka-sample-main-java/activator.properties index 26d450b5b1..c980185eb2 100644 --- a/akka-samples/akka-sample-main-java/activator.properties +++ b/akka-samples/akka-sample-main-java/activator.properties @@ -1,4 +1,4 @@ name=akka-sample-main-java title=Akka Main in Java description=Actor based version of obligatory Hello World program using the generic launcher class akka.Main. -tags=Basics,akka,java,java,starter +tags=Basics,akka,java,starter diff --git a/akka-samples/akka-sample-main-scala/activator.properties b/akka-samples/akka-sample-main-scala/activator.properties index e15e7c3dc9..733461e341 100644 --- a/akka-samples/akka-sample-main-scala/activator.properties +++ b/akka-samples/akka-sample-main-scala/activator.properties @@ -1,4 +1,4 @@ name=akka-sample-main-scala title=Akka Main in Scala description=Actor based version of obligatory Hello World program using the generic launcher class akka.Main. -tags=Basics,akka,java,scala,starter +tags=Basics,akka,scala,starter diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 5303027f20..86df5e9518 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -446,12 +446,19 @@ object AkkaBuild extends Build { id = "akka-samples", base = file("akka-samples"), settings = parentSettings, - aggregate = Seq(camelSample, fsmSample, mainSampleJava, mainSampleScala, helloKernelSample, remoteSample, persistenceSample, clusterSample, multiNodeSample, osgiDiningHakkersSample) + aggregate = Seq(camelSampleJava, camelSampleScala, fsmSample, mainSampleJava, mainSampleScala, helloKernelSample, remoteSample, persistenceSample, clusterSample, multiNodeSample, osgiDiningHakkersSample) ) - lazy val camelSample = Project( - id = "akka-sample-camel", - base = file("akka-samples/akka-sample-camel"), + lazy val camelSampleJava = Project( + id = "akka-sample-camel-java", + base = file("akka-samples/akka-sample-camel-java"), + dependencies = Seq(actor, camel), + settings = sampleSettings ++ Seq(libraryDependencies ++= Dependencies.camelSample) + ) + + lazy val camelSampleScala = Project( + id = "akka-sample-camel-scala", + base = file("akka-samples/akka-sample-camel-scala"), dependencies = Seq(actor, camel), settings = sampleSettings ++ Seq(libraryDependencies ++= Dependencies.camelSample) )