├── project ├── build.properties ├── assembly.sbt ├── plugins.sbt ├── BuildSettings.scala ├── Dependencies.scala └── ActiveMQDemos.scala ├── mqtt ├── dump.pcapng ├── src │ └── main │ │ ├── resources │ │ ├── jndi.properties │ │ └── log4j.properties │ │ └── scala │ │ └── mqtt │ │ ├── MQTTPublisher.scala │ │ └── JMSConsumer.scala └── README.md ├── websockets ├── css │ └── stompdemo.css ├── README.md ├── index.html └── js │ ├── demo.js │ ├── bootstrap.min.js │ └── jquery-2.1.1.min.js ├── fabric-fail-over ├── src │ └── main │ │ ├── resources │ │ ├── jndi.properties │ │ └── log4j.properties │ │ └── scala │ │ └── failover │ │ ├── FailOverConsumer.scala │ │ └── FailoverProducer.scala └── readme.md ├── fail-over ├── src │ └── main │ │ ├── resources │ │ ├── jndi.properties │ │ └── log4j.properties │ │ ├── scala │ │ └── failover │ │ │ ├── FailoverClient.scala │ │ │ └── FailOverConsumer.scala │ │ └── etc │ │ ├── activemq-brokerOne.xml │ │ └── activemq-brokerTwo.xml ├── readme.md └── pom.xml ├── exclusive-consumer └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ └── scala │ └── ExclusiveConsumer.scala ├── request-response └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ └── scala │ └── reqrep │ ├── Consumer.scala │ └── Producer.scala ├── virtual-topics └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ └── scala │ └── virtualtopics │ └── ootb │ ├── TopicPublisher.scala │ └── VirtualTopicQueueConsumer.scala ├── composite-destination └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ ├── etc │ └── composite-queue.conf.xml │ └── scala │ └── compositedestinations │ └── BroadCastingQueueSender.scala ├── protobuf └── src │ └── main │ ├── protobuf │ └── registrant.proto │ └── scala │ └── demo │ └── ProtobufApp.scala ├── embedded-broker ├── README.md └── src │ └── main │ ├── scala │ ├── spring │ │ └── SpringDemo.scala │ └── embedded │ │ └── EmbeddedDemo.scala │ └── resources │ ├── log4j.properties │ └── spring │ └── spring-config.xml ├── wildcards └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ └── scala │ └── wildcards │ ├── WildcardConsumer.scala │ └── Producer.scala ├── jms-jndi └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ ├── java │ └── demo │ │ ├── JmsDemo.java │ │ └── JmsDemoConsumer.java │ └── scala │ └── jms │ ├── Producer.scala │ └── Consumer.scala ├── broker-network └── src │ └── main │ ├── resources │ ├── jndi.properties │ └── log4j.properties │ └── scala │ └── network │ └── BrokerNetwork.scala ├── .gitignore ├── util └── src │ └── main │ └── scala │ └── demo │ └── Helper.scala ├── README.md └── stomp-telnet └── README.md /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.7 -------------------------------------------------------------------------------- /project/assembly.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2") 2 | 3 | -------------------------------------------------------------------------------- /mqtt/dump.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rparree/activemq-demos/HEAD/mqtt/dump.pcapng -------------------------------------------------------------------------------- /websockets/css/stompdemo.css: -------------------------------------------------------------------------------- 1 | #receivedMessages pre { 2 | font-family: "Courier New", Courier, monospace; 3 | } 4 | 5 | body { 6 | padding: 20px; 7 | } -------------------------------------------------------------------------------- /fabric-fail-over/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 2 | 3 | 4 | connectionFactoryNames = myJmsFactory 5 | queue.FailOverQueue = demo.FailOverQueue 6 | -------------------------------------------------------------------------------- /fail-over/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 2 | java.naming.provider.url = failover:(tcp://localhost:61616,tcp://localhost:61617) 3 | 4 | connectionFactoryNames = myJmsFactory 5 | queue.FailOverQueue = demo.FailOverQueue 6 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | 2 | //addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0") 3 | 4 | addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.7.0") 5 | 6 | //addSbtPlugin("com.edc4it" % "sbt-activemq" % "1.0.0-SNAPSHOT") 7 | 8 | addSbtPlugin("com.github.gseitz" % "sbt-protobuf" % "0.4.0") 9 | 10 | 11 | -------------------------------------------------------------------------------- /exclusive-consumer/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | 3 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 4 | java.naming.provider.url = tcp://localhost:61616 5 | 6 | connectionFactoryNames = myJmsFactory 7 | queue.xclusive = demo.xclusive 8 | -------------------------------------------------------------------------------- /request-response/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 3 | java.naming.provider.url = tcp://localhost:61616 4 | 5 | 6 | connectionFactoryNames = myJmsFactory 7 | queue.queue/reqres = demo.ReqResQueue 8 | -------------------------------------------------------------------------------- /virtual-topics/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | 3 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 4 | java.naming.provider.url = tcp://localhost:61616 5 | 6 | connectionFactoryNames = myJmsFactory 7 | topic.SampleTopic= VirtualTopic.SampleTopic -------------------------------------------------------------------------------- /composite-destination/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | 3 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 4 | java.naming.provider.url = tcp://localhost:61616 5 | 6 | connectionFactoryNames = myJmsFactory 7 | queue.BroadCastingQueue= demo.BroadCastingQueue -------------------------------------------------------------------------------- /protobuf/src/main/protobuf/registrant.proto: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | option java_outer_classname="RegistrantProtos"; 4 | 5 | message Registrant { 6 | 7 | required string username = 1; 8 | required string email = 2; 9 | required GenderType gender =3; 10 | 11 | enum GenderType { 12 | FEMALE = 0; 13 | MALE = 1; 14 | } 15 | 16 | 17 | 18 | } -------------------------------------------------------------------------------- /embedded-broker/README.md: -------------------------------------------------------------------------------- 1 | # Embedded demos (and Persistence) 2 | 3 | ## EmbeddedDemo 4 | 5 | Simple embedded example with a vm connector on thread sens messages, main thread consumes them. 6 | 7 | ## SpringDemo 8 | 9 | This demo also demonstrates the use of a jdbc journalled 10 | 11 | ```bash 12 | $ watch -d -c -n 5 'mysql activemq --execute "select count(*) from ACTIVEMQ_MSGS"' 13 | ``` 14 | 15 | It will take ~30 seconds before the checkpoint -------------------------------------------------------------------------------- /wildcards/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | 3 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 4 | java.naming.provider.url = tcp://localhost:61616 5 | 6 | connectionFactoryNames = myJmsFactory 7 | queue.news.europe = demo.news.europe 8 | queue.news.africa = demo.news.africa 9 | queue.news.asia = demo.news.asia 10 | queue.news.america = demo.news.america 11 | -------------------------------------------------------------------------------- /protobuf/src/main/scala/demo/ProtobufApp.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import demo.RegistrantProtos.Registrant.GenderType 4 | 5 | /** 6 | * todo 7 | */ 8 | object ProtobufApp extends App { 9 | 10 | val registrant = RegistrantProtos.Registrant.newBuilder() 11 | .setEmail("jennifer@work.com") 12 | .setGender(GenderType.FEMALE) 13 | .setUsername("jenny").build() 14 | 15 | val array = registrant.toByteArray 16 | 17 | array.foreach(b => print(b + " ")) 18 | 19 | 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /jms-jndi/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | # JNDI properties file to setup the JNDI server within ActiveMQ 3 | 4 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 5 | java.naming.provider.url = tcp://localhost:61616 6 | 7 | #JNDI name of the connection factory 8 | connectionFactoryNames = myJmsFactory 9 | 10 | # register some destinations in JNDI using the form 11 | # queue|topic.[jndiName] = [physicalName] 12 | 13 | queue.queue/JMSDemoQueue = demo.SimpleJMSQueue -------------------------------------------------------------------------------- /mqtt/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # suppress inspection "UnusedProperty" for whole file 2 | # JNDI properties file to setup the JNDI server within ActiveMQ 3 | 4 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 5 | java.naming.provider.url = tcp://localhost:61616?jms.clientID=client1 6 | 7 | #JNDI name of the connection factory 8 | connectionFactoryNames = myJmsFactory 9 | 10 | # register some destinations in JNDI using the form 11 | # queue|topic.[jndiName] = [physicalName] 12 | 13 | topic.JMSDemoTopic = .topic.demo -------------------------------------------------------------------------------- /broker-network/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | # JNDI properties file to setup the JNDI server within ActiveMQ 2 | 3 | # 4 | # Default JNDI properties settings 5 | # 6 | java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory 7 | java.naming.provider.url = tcp://localhost:61616 8 | 9 | # 10 | # Set the connection factory name(s) as well as the destination names. The connection factory name(s) 11 | # as well as the second part (after the dot) of the left hand side of the destination definition 12 | # must be used in the JNDI lookups. 13 | # 14 | connectionFactoryNames = myJmsFactory 15 | queue.queue/reqres = demo.ReqResQueue 16 | -------------------------------------------------------------------------------- /fail-over/readme.md: -------------------------------------------------------------------------------- 1 | ## start the brokers 2 | 3 | This demo uses two fuse instances sharing the same kahadb repo via 4 | docker volumes. 5 | 6 | Start the first broker and map to port 61616 7 | 8 | ```shell 9 | docker run -d -p 8181:8181 -p 8101:8101 \ 10 | --name fuse1 -p 61616:61616 \ 11 | -v /tmp/fuse/kahadb:/opt/jboss/jboss-fuse/kahadb \ 12 | rparree/jboss-fuse-full-admin 13 | ``` 14 | 15 | Start the first broker and map to port 61617 16 | 17 | ```shell 18 | docker run -d -p 8182:8181 -p 8102:8101 \ 19 | --name fuse2 -p 61617:61616 \ 20 | -v /tmp/fuse/kahadb:/opt/jboss/jboss-fuse/kahadb \ 21 | rparree/jboss-fuse-full-admin 22 | ``` -------------------------------------------------------------------------------- /embedded-broker/src/main/scala/spring/SpringDemo.scala: -------------------------------------------------------------------------------- 1 | package spring 2 | 3 | import org.springframework.context.support.ClassPathXmlApplicationContext 4 | import org.springframework.scala.jms.core.JmsTemplate 5 | 6 | /** 7 | * todo 8 | */ 9 | object SpringDemo extends App { 10 | 11 | val context = new ClassPathXmlApplicationContext("/spring/spring-config.xml") 12 | 13 | val template = context.getBean(classOf[JmsTemplate]) 14 | 15 | 16 | 17 | 18 | println("Enter message to send (type exit to quit)") 19 | for (message <- io.Source.stdin.getLines().takeWhile(_ != "exit")) { 20 | template.convertAndSend("queue/Test", message) 21 | } 22 | 23 | println("exiting...") 24 | 25 | context.close() 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /project/BuildSettings.scala: -------------------------------------------------------------------------------- 1 | import sbt.Keys._ 2 | import sbt._ 3 | 4 | object BuildSettings { 5 | 6 | lazy val basicSettings = Seq( 7 | version := "0.1.0-SNAPSHOT", 8 | organization := "com.edc4it", 9 | startYear := Some(2014), 10 | licenses := Seq("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt")), 11 | scalaVersion := "2.11.7", 12 | crossPaths := false, 13 | resolvers ++= Dependencies.resolutionRepos, 14 | scalacOptions ++= Seq("-target:jvm-1.8", "-deprecation", "-Xexperimental","-language:implicitConversions"), 15 | javacOptions in compile ++= Seq("-source", "1.8", "-target", "1.8"), 16 | javacOptions in doc ++= Seq("-source", "1.8"), 17 | publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath + "/.m2/repository"))) 18 | ) 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /fail-over/src/main/scala/failover/FailoverClient.scala: -------------------------------------------------------------------------------- 1 | package failover 2 | 3 | import javax.jms.{ConnectionFactory, Destination} 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper._ 7 | import org.springframework.scala.jms.core.JmsTemplate 8 | import resource._ 9 | 10 | /** 11 | * todo 12 | */ 13 | object FailoverClient extends App { 14 | 15 | for (context <- managed(new InitialContext)) { 16 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 17 | val queue = context.lookup("FailOverQueue").asInstanceOf[Destination] 18 | for (factory <- singleConnectionFactory(cnf)) { 19 | val template = new JmsTemplate(factory) 20 | 21 | for (i <- 1 until 100000) 22 | template.convertAndSend(queue, s"message $i") 23 | 24 | Thread.sleep(200) 25 | 26 | } 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /mqtt/src/main/scala/mqtt/MQTTPublisher.scala: -------------------------------------------------------------------------------- 1 | package mqtt 2 | 3 | import org.fusesource.hawtbuf.UTF8Buffer 4 | import org.fusesource.mqtt.client.{MQTT, QoS} 5 | 6 | /** 7 | * todo 8 | */ 9 | object MQTTPublisher extends App { 10 | 11 | 12 | val mqtt = new MQTT() 13 | mqtt.setHost("localhost", 1883) 14 | println("v1") 15 | // mqtt.setCleanSession(true) 16 | // mqtt.setKeepAlive(1000) 17 | mqtt.setUserName("admin") 18 | mqtt.setPassword("admin") 19 | // mqtt.setWillMessage("my last will") 20 | 21 | val connection = mqtt.futureConnection() 22 | connection.connect().await() 23 | 24 | 25 | val topic = new UTF8Buffer("/topic/demo") 26 | val msg = new UTF8Buffer("hello") 27 | //for (i <- 1 until 1000) { 28 | val future = connection.publish(topic, msg, QoS.AT_LEAST_ONCE, false) 29 | // } 30 | 31 | connection.disconnect().await() 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /fail-over/src/main/scala/failover/FailOverConsumer.scala: -------------------------------------------------------------------------------- 1 | package failover 2 | 3 | import javax.jms.{ConnectionFactory, Destination} 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper 7 | import demo.Helper._ 8 | import org.springframework.scala.jms.core.JmsTemplate 9 | import resource._ 10 | 11 | /** 12 | * todo 13 | */ 14 | object FailOverConsumer extends App { 15 | 16 | 17 | 18 | 19 | for (context <- managed(new InitialContext)) { 20 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 21 | 22 | 23 | val queue = context.lookup("FailOverQueue").asInstanceOf[Destination] 24 | for (factory <- singleConnectionFactory(cnf)) { 25 | val template = new JmsTemplate(factory) 26 | 27 | template.javaTemplate.setReceiveTimeout(1000000) 28 | Helper.receiveFromTemplateAndPrintText(template,queue) 29 | } 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /virtual-topics/src/main/scala/virtualtopics/ootb/TopicPublisher.scala: -------------------------------------------------------------------------------- 1 | package virtualtopics.ootb 2 | 3 | import javax.jms.{ConnectionFactory, Topic} 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper._ 7 | import org.springframework.scala.jms.core.JmsTemplate 8 | import resource._ 9 | 10 | /** 11 | * todo 12 | */ 13 | object TopicPublisher extends App { 14 | 15 | for (context <- managed(new InitialContext)) { 16 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 17 | val topic = context.lookup("SampleTopic").asInstanceOf[Topic] 18 | for (factory <- singleConnectionFactory(cnf)) { 19 | val template = new JmsTemplate(factory) 20 | 21 | println("Enter message to send (type exit to quit)") 22 | for (message <- io.Source.stdin.getLines().takeWhile(_ != "exit")) { 23 | template.convertAndSend(topic, message) 24 | } 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /wildcards/src/main/scala/wildcards/WildcardConsumer.scala: -------------------------------------------------------------------------------- 1 | package wildcards 2 | 3 | import javax.naming.InitialContext 4 | 5 | import demo.Helper._ 6 | import org.apache.activemq.ActiveMQConnectionFactory 7 | import org.springframework.scala.jms.core.JmsTemplate 8 | import resource._ 9 | 10 | /** 11 | * todo 12 | */ 13 | object WildcardConsumer extends App { 14 | 15 | 16 | for (context <- managed(new InitialContext)) { 17 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ActiveMQConnectionFactory] 18 | for (factory <- singleConnectionFactory(cnf)) { 19 | val template = new JmsTemplate(factory) 20 | 21 | val queue = template.execute(s => s.createQueue("demo.news.*")) 22 | template.javaTemplate.setReceiveTimeout(10000) 23 | println("Starting to receive (timeout is 10s)") 24 | 25 | demo.Helper.receiveFromTemplateAndPrintText(template,queue) 26 | 27 | 28 | } 29 | 30 | 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /composite-destination/src/main/etc/composite-queue.conf.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /jms-jndi/src/main/java/demo/JmsDemo.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | import org.apache.activemq.protobuf.BufferInputStream; 4 | 5 | import javax.jms.*; 6 | import javax.naming.InitialContext; 7 | import javax.naming.NamingException; 8 | import java.io.BufferedInputStream; 9 | import java.io.FileInputStream; 10 | 11 | /** 12 | * todo 13 | */ 14 | public class JmsDemo { 15 | 16 | public static void main(String[] args) throws Exception { 17 | 18 | InitialContext context = new InitialContext(); //looks for jndi.properties 19 | ConnectionFactory cnf = (ConnectionFactory) context.lookup("myJmsFactory"); 20 | Destination destination = (Destination) context.lookup("queue/JMSDemoQueue"); 21 | 22 | Connection connection = cnf.createConnection("admin", "admin"); 23 | Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); 24 | 25 | MessageProducer producer = session.createProducer(destination); 26 | Message msg = session.createTextMessage("hello some text from legacy Java"); 27 | producer.send(msg); 28 | 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /composite-destination/src/main/scala/compositedestinations/BroadCastingQueueSender.scala: -------------------------------------------------------------------------------- 1 | package compositedestinations 2 | 3 | import javax.jms.{ConnectionFactory, Destination} 4 | import javax.naming.InitialContext 5 | 6 | import org.springframework.scala.jms.core.JmsTemplate 7 | import resource._ 8 | 9 | /** 10 | * todo 11 | */ 12 | object BroadCastingQueueSender extends App { 13 | 14 | for (context <- managed(new InitialContext)) { 15 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 16 | val queue = context.lookup("BroadCastingQueue").asInstanceOf[Destination] 17 | for (factory <- demo.Helper.singleConnectionFactory(cnf)) { 18 | val template = new JmsTemplate(factory) 19 | 20 | template.convertAndSend(queue, "message 1") 21 | template.send(queue)(s => { 22 | val textMessage = s.createTextMessage("message 2 [gold]") 23 | textMessage.setObjectProperty("level", "gold") 24 | textMessage 25 | }) 26 | 27 | println("Have sent the two messages, check queue count in hawtio") 28 | 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /jms-jndi/src/main/scala/jms/Producer.scala: -------------------------------------------------------------------------------- 1 | package jms 2 | 3 | import javax.jms.{ConnectionFactory, Destination, Session} 4 | import javax.naming.InitialContext 5 | 6 | import resource._ 7 | 8 | 9 | /** 10 | * todo 11 | */ 12 | object Producer extends App { 13 | 14 | // myJmsFactory, queue/JMSDemoQueue (see jndi.properties) 15 | val destinationName = "queue/JMSDemoQueue" // "dynamicQueues/FooQueue" 16 | 17 | for (ctx <- managed(new InitialContext())) { 18 | val factory = ctx.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 19 | val destination = ctx.lookup(destinationName).asInstanceOf[Destination] 20 | 21 | for (connection <- managed(factory.createConnection("admin","admin")); 22 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 23 | producer <- managed(session.createProducer(destination))) { 24 | 25 | println("Enter message to send (type exit to quit)") 26 | 27 | for (message <- io.Source.stdin.getLines().takeWhile(_ != "exit")) { 28 | producer.send(session.createTextMessage(message)) 29 | } 30 | 31 | println("exiting...") 32 | 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /mqtt/src/main/scala/mqtt/JMSConsumer.scala: -------------------------------------------------------------------------------- 1 | package mqtt 2 | 3 | import javax.jms._ 4 | import javax.naming.InitialContext 5 | 6 | import resource._ 7 | 8 | 9 | object JMSConsumer extends App { 10 | 11 | 12 | def marshall(message: BytesMessage): Unit = { 13 | val b = new Array[Byte](message.getBodyLength.toInt) 14 | message.readBytes(b) 15 | val msg = new String(b, "UTF-8") 16 | println(s"received $msg") 17 | } 18 | 19 | for (ctx <- managed(new InitialContext())) { 20 | val factory = ctx.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 21 | val destinationName = "JMSDemoTopic" 22 | val topic = ctx.lookup(destinationName).asInstanceOf[Topic] 23 | 24 | for (connection <- managed(factory.createConnection()); 25 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 26 | consumer <- managed(session.createDurableSubscriber(topic, "subscriber"))) { 27 | 28 | 29 | connection.start() 30 | Option(consumer.receive(30000)) match { 31 | case Some(m: BytesMessage) => marshall(m) 32 | case None => println("Timeout") 33 | } 34 | } 35 | 36 | 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /wildcards/src/main/scala/wildcards/Producer.scala: -------------------------------------------------------------------------------- 1 | package wildcards 2 | 3 | import java.util.Properties 4 | import javax.jms.{ConnectionFactory, Queue} 5 | import javax.naming.InitialContext 6 | 7 | import demo.Helper.singleConnectionFactory 8 | import org.springframework.scala.jms.core.JmsTemplate 9 | import resource._ 10 | 11 | import scala.collection.JavaConversions._ 12 | 13 | /** 14 | * todo 15 | */ 16 | object Producer extends App { 17 | 18 | val jndiProps = new Properties() 19 | jndiProps.load(getClass.getResourceAsStream("/jndi.properties")) 20 | 21 | for (context <- managed(new InitialContext)) { 22 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 23 | val queues = jndiProps.filterKeys(s => s.startsWith("queue.")).keysIterator.map(n => n.stripPrefix("queue.")).map(name => context.lookup(name).asInstanceOf[Queue]) 24 | 25 | for (factory <- singleConnectionFactory(cnf)) { 26 | val template = new JmsTemplate(factory) 27 | 28 | queues.foreach { q => 29 | println(s"Sent message to ${q.getQueueName}") 30 | template.convertAndSend(q, s"message on ${q.getQueueName}") 31 | } 32 | 33 | } 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /virtual-topics/src/main/scala/virtualtopics/ootb/VirtualTopicQueueConsumer.scala: -------------------------------------------------------------------------------- 1 | package virtualtopics.ootb 2 | 3 | import javax.jms.ConnectionFactory 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper 7 | import demo.Helper._ 8 | import org.apache.activemq.ActiveMQConnectionFactory 9 | import org.springframework.scala.jms.core.JmsTemplate 10 | import resource._ 11 | 12 | /** 13 | * todo 14 | */ 15 | object VirtualTopicQueueConsumer extends App { 16 | 17 | val consumerName = readLine("Consumer name: ") 18 | 19 | 20 | for (context <- managed(new InitialContext)) { 21 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 22 | 23 | val queueName = s"Consumer.$consumerName.VirtualTopic.SampleTopic" // or even Consumer.$consumerName.VirtualTopic.* 24 | 25 | for (factory <- singleConnectionFactory(cnf)) { 26 | val template = new JmsTemplate(factory) 27 | 28 | 29 | 30 | val queue = template.execute(s => s.createQueue(queueName)) 31 | println(s"receiving on queue: $queueName") 32 | template.javaTemplate.setReceiveTimeout(10000) 33 | Helper.receiveFromTemplateAndPrintText(template,queue) 34 | 35 | } 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /jms-jndi/src/main/scala/jms/Consumer.scala: -------------------------------------------------------------------------------- 1 | package jms 2 | 3 | import javax.jms._ 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper._ 7 | import org.apache.activemq.command.ActiveMQQueue 8 | import resource._ 9 | 10 | import scala.concurrent.duration._ 11 | 12 | 13 | object Consumer extends App { 14 | 15 | // myJmsFactory, queue/JMSDemoQueue (see jndi.properties) 16 | 17 | for (ctx <- managed(new InitialContext())) { 18 | val factory = ctx.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 19 | val destinationName = "queue/JMSDemoQueue" // "dynamicQueues/FooQueue" 20 | val queue = ctx.lookup(destinationName).asInstanceOf[ActiveMQQueue] 21 | 22 | println(s"Receiving from queue with physical name: ${queue.getPhysicalName} and properties ${queue.getProperties} ") 23 | 24 | 25 | 26 | for (connection <- managed(factory.createConnection("admin","admin")); 27 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 28 | consumer <- managed(session.createConsumer(queue))) { 29 | 30 | println("Starting receiving (timeout is 30s)") 31 | connection.start() 32 | 33 | receiveAndPrintText(consumer, 30 seconds) 34 | 35 | 36 | } 37 | } 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /websockets/README.md: -------------------------------------------------------------------------------- 1 | # WebSockets demo 2 | 3 | This is a small demo showing the use of Web Sockets to receive messages in the browser. Purposely it 4 | is not (over) engineered to keep it simple for educational purposes. The code has been made a little DRY, 5 | but not to the extend where it would interfere with demonstration and educational objectives. If you are looking for a 6 | full blown JavaScript STOMP API, i suggest you look at [https://github.com/jmesnil/stomp-websocket](https://github.com/jmesnil/stomp-websocket) 7 | 8 | ## Setup 9 | 10 | Ensure the following connector is enabled 11 | 12 | ```xml 13 | 14 | ``` 15 | 16 | Also make sure you have a http server installed. 17 | Easiest is to use the [http-server](https://www.npmjs.org/package/http-server) available from npm. 18 | 19 | ## Use the demo 20 | 21 | Serve the pages off the same computer as where ActiveMQ is running. Then click the connect button. IF connection is 22 | successful a subscription form will appear. Supply the name of the destination (queue or topic) and click `subscribe` 23 | 24 | Then use the Hawtio console to send messages to the destination. Observe how the messages appear on the page (newest one in the top) -------------------------------------------------------------------------------- /jms-jndi/src/main/java/demo/JmsDemoConsumer.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | import org.apache.activemq.ActiveMQConnectionFactory; 4 | import org.apache.activemq.broker.region.*; 5 | 6 | import javax.jms.*; 7 | import javax.jms.Destination; 8 | import javax.naming.InitialContext; 9 | 10 | /** 11 | * todo 12 | */ 13 | public class JmsDemoConsumer { 14 | 15 | public static void main(String[] args) throws Exception { 16 | 17 | InitialContext initialContext = new InitialContext(); 18 | ConnectionFactory cnf = (ConnectionFactory) initialContext.lookup("myJmsFactory"); 19 | Destination destination = (Destination) initialContext.lookup("queue/JMSDemoQueue"); 20 | Connection connection = cnf.createConnection("admin", "admin"); 21 | Session session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE); 22 | MessageConsumer consumer = session.createConsumer(destination); 23 | consumer.setMessageListener((Message m)->{ 24 | TextMessage tms = (TextMessage) m; 25 | try { 26 | System.out.append("Received message with text").println(tms.getText()); 27 | } catch (JMSException e) { 28 | System.out.println("ooops."); 29 | } 30 | }); 31 | 32 | connection.start(); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | 15 | ### JetBrains template 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 17 | 18 | ## Directory-based project format 19 | .idea/ 20 | # if you remove the above rule, at least ignore user-specific stuff: 21 | # .idea/workspace.xml 22 | # .idea/tasks.xml 23 | # and these sensitive or high-churn files: 24 | # .idea/dataSources.ids 25 | # .idea/dataSources.xml 26 | # .idea/sqlDataSources.xml 27 | # .idea/dynamic.xml 28 | 29 | ## File-based project format 30 | *.ipr 31 | *.iml 32 | *.iws 33 | 34 | ## Additional for IntelliJ 35 | out/ 36 | 37 | # generated by mpeltonen/sbt-idea plugin 38 | .idea_modules/ 39 | 40 | # generated by JIRA plugin 41 | atlassian-ide-plugin.xml 42 | 43 | # generated by Crashlytics plugin (for Android Studio and Intellij) 44 | com_crashlytics_export_strings.xml 45 | 46 | 47 | ### Linux template 48 | *~ 49 | 50 | # KDE directory preferences 51 | .directory 52 | 53 | 54 | ### Maven template 55 | target/ 56 | pom.xml.tag 57 | pom.xml.releaseBackup 58 | pom.xml.versionsBackup 59 | pom.xml.next 60 | release.properties 61 | 62 | ### For this project 63 | 64 | activemq/ 65 | 66 | -------------------------------------------------------------------------------- /mqtt/README.md: -------------------------------------------------------------------------------- 1 | # MQTT demo 2 | 3 | ## Setup 4 | 5 | **Important** At this moment running from sbt does not work (probably context loader problem). 6 | For now run using intellij. 7 | 8 | Make sure the mqtt connector is enabled in activemq. 9 | 10 | The mqtt protocol's specification can be downloaded from [here](http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/MQTT_V3.1_Protocol_Specific.pdf) 11 | 12 | ## Running 13 | 14 | 1. Run the `mqtt.JMSConsumer` using SBT 15 | 2. Run the `mqtt.MQTTPublisher` using your IDE 16 | 17 | ## Sniffing 18 | 19 | Use the following to illustrate the data packets send between client and broker: 20 | 21 | ```bash 22 | $ sudo tcpflow -c -D -i lo tcp port 1883 23 | ``` 24 | 25 | Explanation of the flags: 26 | 27 | - `-c` to output to console as apposed to a file 28 | - `-D` to output in HEX as apposed to text 29 | - '-i lo' capture on localhost network 30 | - 'tcp port 1883` capture traffic to/from port 1883 31 | 32 | The output should include 4 messages (in dialogue style) 33 | 34 | 1. message: 1030 ... (1 0|00|0 0x30) means a `CONNECT` followed by 48 (0x30) bytes 35 | 2. message: 2002 ... (2 0|00|0 0x02) means a `CONNACK` followed by 2 bytes 36 | 3. message: 3214 ... (3 0|01|0 0x14) means a `PUBLISH` with a QoS 1 (at least once) followed by 20 bytes 37 | 4. message: 4002 0001 (4 ...) means a `PUBACK`, followed by 2 bytes (which contain the 16-bit unsigned message id: 1) 38 | 39 | -------------------------------------------------------------------------------- /fabric-fail-over/src/main/scala/failover/FailOverConsumer.scala: -------------------------------------------------------------------------------- 1 | package failover 2 | 3 | import javax.jms.{ConnectionFactory, Destination} 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper 7 | import demo.Helper._ 8 | import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter 9 | import org.springframework.scala.jms.core.JmsTemplate 10 | import resource._ 11 | 12 | /** 13 | * todo 14 | */ 15 | object FailOverConsumer extends App { 16 | 17 | // System.setProperty("java.naming.provider.url", "discovery:(fabric:amq-west)") 18 | System.setProperty("java.naming.provider.url", 19 | "failover:(tcp://localhost:19000,tcp://localhost:19001)") 20 | // System.setProperty("zookeeper.password", "masterkey") 21 | 22 | 23 | 24 | 25 | for (context <- managed(new InitialContext)) { 26 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 27 | val s = new UserCredentialsConnectionFactoryAdapter() 28 | s.setTargetConnectionFactory(cnf) 29 | s.setUsername("admin") 30 | s.setPassword("admin") 31 | 32 | val queue = context.lookup("FailOverQueue").asInstanceOf[Destination] 33 | for (factory <- singleConnectionFactory(s)) { 34 | val template = new JmsTemplate(factory) 35 | 36 | template.javaTemplate.setReceiveTimeout(10000) 37 | Helper.receiveFromTemplateAndPrintText(template,queue) 38 | } 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /fabric-fail-over/src/main/scala/failover/FailoverProducer.scala: -------------------------------------------------------------------------------- 1 | package failover 2 | 3 | import javax.jms.{Destination, ConnectionFactory} 4 | import javax.naming.{Context, InitialContext} 5 | 6 | 7 | import demo.Helper._ 8 | import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter 9 | import org.springframework.scala.jms.core.JmsTemplate 10 | import resource._ 11 | 12 | /** 13 | * todo 14 | */ 15 | object FailoverProducer extends App { 16 | 17 | 18 | // System.setProperty("java.naming.provider.url", "discovery:(fabric:amq-east)?reconnectDelay=1000") 19 | // System.setProperty("zookeeper.password", "masterkey") 20 | 21 | // System.setProperty("zookeeper.url", "localhost:33337") 22 | System.setProperty("java.naming.provider.url", "failover:(tcp://localhost:18000,tcp://localhost:18001)") 23 | 24 | 25 | for (context <- managed(new InitialContext)) { 26 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 27 | val queue = context.lookup("FailOverQueue").asInstanceOf[Destination] 28 | val s = new UserCredentialsConnectionFactoryAdapter() 29 | s.setTargetConnectionFactory(cnf) 30 | s.setUsername("admin") 31 | s.setPassword("admin") 32 | for (factory <- singleConnectionFactory(s)) { 33 | val template = new JmsTemplate(factory) 34 | 35 | for (i <- 1 until 100) { 36 | template.convertAndSend(queue, s"message $i") 37 | println(s"sent message $i") 38 | } 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /fabric-fail-over/readme.md: -------------------------------------------------------------------------------- 1 | fa### Setup the fabric 2 | 3 | Start fuse in docker: 4 | 5 | ``` 6 | docker run -Pd \ 7 | -p 2181:2181 \ 8 | -p 8181:8181 \ 9 | -p 8101:8101 \ 10 | -p 18000-18005:18000-18005 \ 11 | -p 19000-19005:19000-19005 \ 12 | --name mq-fabric \ 13 | rparree/jboss-fuse-full-admin 14 | ``` 15 | 16 | Create the Fabric 17 | 18 | ``` 19 | JBossFuse:karaf@root> fabric:create --zookeeper-password masterkey 20 | ``` 21 | 22 | create the containers 23 | 24 | ``` 25 | JBossFuse:karaf@root> container-create-child --jmx-user admin --jmx-password admin east 2 26 | JBossFuse:karaf@root> container-create-child --jmx-user admin --jmx-password admin west 2 27 | ```` 28 | 29 | Optionally delete the broker on the root container 30 | 31 | ``` 32 | JBossFuse:karaf@root> config:delete org.fusesource.mq.fabric.server. 33 | JBossFuse:karaf@root> shell:exec mv etc/org.fusesource.mq.fabric.server-default.cfg . 34 | ``` 35 | 36 | Create the east-side 37 | ``` 38 | JBossFuse:karaf@root> fabric:mq-create --group amq-east \ 39 | --networks amq-west \ 40 | --networks-username admin --networks-password admin \ 41 | --ports "openwire=\${port:18000,18100}" \ 42 | --data /tmp/activemq/data/amq-east \ 43 | --assign-container east1,east2 demo-east-profile 44 | ``` 45 | 46 | Create the west-side 47 | ``` 48 | JBossFuse:karaf@root> fabric:mq-create --group amq-west \ 49 | --networks amq-east \ 50 | --networks-username admin --networks-password admin \ 51 | --ports "openwire=\${port:19000,19100}" \ 52 | --data /tmp/activemq/data/amq-west \ 53 | --assign-container west1,west2 demo-west-profile 54 | ``` 55 | -------------------------------------------------------------------------------- /mqtt/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /fail-over/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /jms-jndi/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /wildcards/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /broker-network/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /exclusive-consumer/src/main/scala/ExclusiveConsumer.scala: -------------------------------------------------------------------------------- 1 | import java.util.Properties 2 | import javax.jms._ 3 | import javax.naming.InitialContext 4 | import scala.concurrent.duration._ 5 | import resource._ 6 | 7 | /** 8 | * todo 9 | */ 10 | object ExclusiveConsumer extends App { 11 | 12 | 13 | val consumerName = readLine("Consumer name: ") 14 | val digits = """(\d+)""".r 15 | val priority = readLine("Priority: ") match { 16 | case digits(d) => Some(d) 17 | case _ => None 18 | } 19 | 20 | println(s"name $consumerName with priority: ${priority.getOrElse("none")}") 21 | 22 | val jndiProps = new Properties() 23 | jndiProps.load(getClass.getResourceAsStream("/jndi.properties")) 24 | 25 | 26 | for (context <- managed(new InitialContext)) { 27 | 28 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 29 | 30 | for (connection <- managed(cnf.createConnection()); 31 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE))) { 32 | 33 | connection.start() 34 | 35 | val xclusiveQueueName = { 36 | val b = StringBuilder.newBuilder 37 | val queue = context.lookup("xclusive").asInstanceOf[Queue] 38 | b.append(queue.getQueueName).append("?consumer.exclusive=true") 39 | b.append(priority.map(s => "&consumer.priority=" + s).getOrElse("")) 40 | b.toString() 41 | } 42 | println(s"Using queue name $xclusiveQueueName") 43 | 44 | 45 | 46 | val xclusiveQueue = session.createQueue(xclusiveQueueName) 47 | for (consumer <- managed(session.createConsumer(xclusiveQueue))) { 48 | 49 | println("Starting receiving (timeout 30 seconds)") 50 | demo.Helper.receiveText(consumer, 30 seconds) { 51 | m => println(s"Received '${m.getText}' by $consumerName") 52 | } 53 | 54 | } 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /virtual-topics/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /embedded-broker/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /exclusive-consumer/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /fabric-fail-over/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /request-response/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /composite-destination/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # 19 | # The logging properties used by the standalone ActiveMQ broker 20 | # 21 | log4j.rootLogger=INFO, stdout 22 | 23 | # CONSOLE appender 24 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 25 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n 27 | 28 | # Log File appender 29 | log4j.appender.logfile=org.apache.log4j.FileAppender 30 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.logfile.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n 32 | log4j.appender.logfile.file=./target/log/exercises.log 33 | log4j.appender.logfile.append=true 34 | 35 | # 36 | # You can change logger levels here. 37 | # 38 | log4j.logger.org.apache.activemq=INFO 39 | log4j.logger.org.apache.activemq.spring=WARN 40 | -------------------------------------------------------------------------------- /request-response/src/main/scala/reqrep/Consumer.scala: -------------------------------------------------------------------------------- 1 | package reqrep 2 | 3 | import javax.jms.{ConnectionFactory, Destination, TextMessage} 4 | import javax.naming.InitialContext 5 | 6 | import demo.Helper.singleConnectionFactory 7 | import org.apache.activemq.DestinationDoesNotExistException 8 | import org.springframework.scala.jms.core.JmsTemplate 9 | import resource._ 10 | 11 | import scala.annotation.tailrec 12 | 13 | object Consumer extends App { 14 | 15 | 16 | for (context <- managed(new InitialContext)) { 17 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 18 | val queue = context.lookup("queue/reqres").asInstanceOf[Destination] 19 | 20 | for (factory <- singleConnectionFactory(cnf)) { 21 | val template = new JmsTemplate(factory) 22 | 23 | 24 | println("Starting receiving. Timeout is 20s") 25 | template.javaTemplate.setReceiveTimeout(20000) 26 | receive() 27 | 28 | @tailrec 29 | def receive(): Unit = { 30 | template.receive(queue) match { 31 | case Some(inMessage: TextMessage) => try { 32 | template.send(inMessage.getJMSReplyTo)( 33 | s => { 34 | val correlationID = inMessage.getJMSCorrelationID 35 | println(s"received message with #$correlationID, sending reply") 36 | val outMsg = s.createTextMessage(inMessage.getText.toUpperCase) 37 | outMsg.setJMSCorrelationID(correlationID) 38 | outMsg 39 | }) 40 | } 41 | catch { 42 | case e if e.getCause.isInstanceOf[DestinationDoesNotExistException] => println("The client already closed the reply queue") 43 | } 44 | receive() 45 | case None => print("received no message (timeout)") 46 | case _ => println("was expecting a text message") 47 | receive() 48 | } 49 | 50 | } 51 | 52 | } 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /util/src/main/scala/demo/Helper.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import javax.jms._ 4 | 5 | import org.springframework.jms.connection.{UserCredentialsConnectionFactoryAdapter, SingleConnectionFactory} 6 | import org.springframework.scala.jms.core.JmsTemplate 7 | import resource._ 8 | 9 | import scala.annotation.tailrec 10 | import scala.concurrent.duration._ 11 | 12 | /** 13 | * todo 14 | */ 15 | object Helper { 16 | def singleConnectionFactory(cnf: ConnectionFactory) = { 17 | val u = new UserCredentialsConnectionFactoryAdapter() 18 | u.setTargetConnectionFactory(cnf) 19 | u.setUsername("admin") 20 | u.setPassword("admin") 21 | val d = new SingleConnectionFactory(u) 22 | makeManagedResource(d) { 23 | _.destroy() 24 | }(Nil) 25 | } 26 | 27 | 28 | val receiveAndPrintText = receiveText(_: MessageConsumer, _: Duration)(m => println(s"received ${m.getText}")) 29 | val receiveFromTemplateAndPrintText = receiveText(_: JmsTemplate, _: Destination)(m => println(s"received ${m.getText}")) 30 | 31 | @tailrec 32 | def receiveText(consumer: MessageConsumer, timeOut: Duration = 10.seconds)(txtReceive: (TextMessage) => Unit): Unit = { 33 | Option(consumer.receive(timeOut.toMillis)) match { 34 | case Some(m: TextMessage) => txtReceive(m) 35 | receiveText(consumer, timeOut)(txtReceive) 36 | case Some(m: Message) => println("Received a non-text message") 37 | receiveText(consumer, timeOut)(txtReceive) 38 | 39 | case None => println("Timed out"); 40 | } 41 | } 42 | 43 | @tailrec 44 | def receiveText(jmsTemplate: JmsTemplate, d: Destination)(txtReceive: (TextMessage) => Unit): Unit = { 45 | jmsTemplate.receive(d) match { 46 | case Some(m: TextMessage) => txtReceive(m) 47 | receiveText(jmsTemplate, d)(txtReceive) 48 | case Some(m: Message) => println("Received a non-text message") 49 | receiveText(jmsTemplate, d)(txtReceive) 50 | 51 | case None => println("Timed out"); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /fail-over/src/main/etc/activemq-brokerOne.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /fail-over/src/main/etc/activemq-brokerTwo.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /request-response/src/main/scala/reqrep/Producer.scala: -------------------------------------------------------------------------------- 1 | package reqrep 2 | 3 | import java.util.UUID 4 | import javax.jms._ 5 | import javax.naming.InitialContext 6 | 7 | import org.springframework.scala.jms.core.JmsTemplate 8 | import resource._ 9 | 10 | 11 | /** 12 | * todo 13 | */ 14 | object Producer extends App { 15 | type CorrelationId = String 16 | 17 | for (context <- managed(new InitialContext)) { 18 | val cnf = context.lookup("myJmsFactory").asInstanceOf[ConnectionFactory] 19 | val queue = context.lookup("queue/reqres").asInstanceOf[Destination] 20 | 21 | for (factory <- demo.Helper.singleConnectionFactory(cnf)) { 22 | val template = new JmsTemplate(factory) 23 | 24 | val replyQueue = template.execute(session => session.createTemporaryQueue()) 25 | 26 | val someStrings = "blink" :: "road" :: Nil 27 | 28 | val requestMap = (someStrings map { 29 | s => 30 | val id = UUID.randomUUID().toString 31 | template.send(queue) { 32 | session => 33 | val msg = session.createTextMessage(s) 34 | msg.setJMSReplyTo(replyQueue) 35 | msg.setJMSCorrelationID(id) 36 | msg 37 | } 38 | println(s"sent $s") 39 | (id, s) 40 | 41 | }).toMap 42 | 43 | template.javaTemplate.setReceiveTimeout(20000) 44 | println("Starting to receive (timout 20s)") 45 | receive() 46 | 47 | def receive(): Unit = { 48 | template.receive(replyQueue) match { 49 | case Some(inMessage: TextMessage) => { 50 | val origStr = requestMap(inMessage.getJMSCorrelationID) 51 | print(s"$origStr -> ${inMessage.getText}") 52 | receive() 53 | } 54 | case Some(msg) => println(s"expected a text message, received $msg") 55 | receive() 56 | case None => println("No more messages receives (timeout)") 57 | } 58 | 59 | } 60 | 61 | 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /project/Dependencies.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | object Dependencies { 4 | 5 | 6 | val springVersion = "3.2.4.RELEASE" 7 | val activeMqVersion = "5.11.0" 8 | val amqVersion = "6.1.1.redhat-449" 9 | val fabricVersion = "1.2.0.redhat-621048" 10 | 11 | 12 | val resolutionRepos = Seq( 13 | "repository.springsource.milestone" at "http://repo.springsource.org/milestone", 14 | "repository.springsource.snapshot" at "http://repo.springsource.org/snapshot", 15 | "fusesource.releases" at "https://repository.jboss.org/nexus/content/repositories/fs-releases/", 16 | "fusesource.ea" at "https://repository.jboss.org/nexus/content/groups/ea/", 17 | "oss.sonatype.org" at "https://oss.sonatype.org/content/repositories/snapshots/" 18 | ) 19 | def compile(deps: ModuleID*): Seq[ModuleID] = deps map (_ % "compile") 20 | def provided(deps: ModuleID*): Seq[ModuleID] = deps map (_ % "provided") 21 | def test(deps: ModuleID*): Seq[ModuleID] = deps map (_ % "test") 22 | def runtime(deps: ModuleID*): Seq[ModuleID] = deps map (_ % "runtime") 23 | 24 | def container(deps: ModuleID*): Seq[ModuleID] = deps map (_ % "container") 25 | val activemq = "org.apache.activemq" % "activemq-all" % activeMqVersion 26 | val scalaARM = "com.jsuereth" %% "scala-arm" % "1.4" 27 | var xbean = "org.apache.xbean" % "xbean-spring" % "3.7" 28 | var activeIO = "org.apache.activemq" % "activeio-core" % "3.1.4" 29 | var mqttClient = "org.fusesource.mqtt-client" % "mqtt-client" % "1.10" 30 | 31 | // Some reusable sets 32 | var springScalaJMS = Seq( 33 | "org.springframework.scala" %% "spring-scala" % "1.0.0.BUILD-SNAPSHOT", 34 | "org.springframework" % "spring-jms" % springVersion, 35 | 36 | "commons-pool" % "commons-pool" % "1.6" 37 | ) 38 | var springDB = Seq( 39 | "org.springframework" % "spring-jdbc" % springVersion, 40 | "com.mchange" % "c3p0" % "0.9.2.1", 41 | "mysql" % "mysql-connector-java" % "5.1.22", 42 | "commons-pool" % "commons-pool" % "1.6" 43 | ) 44 | 45 | var fabric = Seq( 46 | // "org.jboss.amq" % "mq-fabric" % amqVersion, 47 | "io.fabric8" % "fabric-groups" % fabricVersion, 48 | "io.fabric8" % "fabric-zookeeper" % fabricVersion 49 | 50 | ) 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # activemq-demos 3 | 4 | Please consult the setup instructions further below. 5 | 6 | - **jms-jndi** Very simple demo showing use of `jndi.properties` and `dynamicQueues` 7 | - **request-response** Basic Request-Response MEP implementation (uses scala-spring for JMS templates). Only one of 8 | the sent messages is correlated, to illustrate it works. Run the consumer first 9 | - **broker-network** Demo which sets up a network of three brokers. Then sending on to broker1 and 10 | receiving on broker2 and broker3. Use `setupBroker1AndSendMessage(None)` to setup the brokers without a network to see 11 | the difference. Jolokia enabled; connect using Hamtio Chrome extension (port: `8777`, path : `/jolokia`, username/password: `smx/xms`: 12 | - **wildcards** shows how messages sent to "demo.news.europe|asia|etc" are received using `demo.news.*` 13 | - **virtual-topics** illustrates a Queue receiver on a topic. 14 | - **exclusive-consumer** demonstrates exclusive consumption on a queue. 15 | - **composite-destination** You need to manually copy/paste the composite destination into the activemq configuration 16 | file (see [composite-queue.conf.xml](composite-destination/src/main/etc/composite-queue.conf.xml)). Then 17 | run the client (using maven) and observe the queue size in hawtio 18 | - **fail-over** Run the two brokers using the [sbt-activemq](https://github.com/edc4it/sbt-activemq/) plugin. You can 19 | eiher start them in the same sbt process or in separate processes (which makes killing the broker possible). 20 | - **stomp-telnet** has its own [README.md](stomp-telnet/README.md) 21 | - **websockets** has its own [README.md](websockets/README.md) 22 | - **embedded-broker** Showing embedde brokers as well as demonstrating jdbc journalled persistence. Has its own 23 | [README.md](embedded-broker/README.md) 24 | - **mqtt** Illustrates use of mqtt protocol. Has its own [README.md](mqtt/README.md) 25 | 26 | 27 | # Setup 28 | 29 | 30 | These demos have been developed and tested with ActiveMQ 5.10, Java 7-8 and SBT 0.13.5. 31 | 32 | ## ActiveMQ 33 | 34 | You could run against the standalone version, or prepare a kara instance. The instructions for setting up 35 | your karaf instance are below. 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /embedded-broker/src/main/resources/spring/spring-config.xml: -------------------------------------------------------------------------------- 1 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 32 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /websockets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 | 21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 | 33 | 34 | 35 | 36 | 74 | -------------------------------------------------------------------------------- /embedded-broker/src/main/scala/embedded/EmbeddedDemo.scala: -------------------------------------------------------------------------------- 1 | package embedded 2 | 3 | import java.nio.file.FileSystems 4 | import javax.jms.Session 5 | 6 | import org.apache.activemq.ActiveMQConnectionFactory 7 | import org.apache.activemq.broker.BrokerService 8 | import org.apache.activemq.command.ActiveMQQueue 9 | import org.apache.activemq.store.kahadb.KahaDBStore 10 | import resource._ 11 | 12 | import scala.annotation.tailrec 13 | import scala.concurrent.ExecutionContext.Implicits.global 14 | import scala.concurrent._ 15 | 16 | 17 | /** 18 | * todo 19 | */ 20 | object EmbeddedDemo extends App { 21 | 22 | 23 | val broker = startBroker 24 | 25 | val factory = new ActiveMQConnectionFactory("vm:local?create=false") 26 | factory.setUseAsyncSend(true) 27 | for (connection <- managed(factory.createConnection())) { 28 | val pf = future { 29 | 30 | for (session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 31 | producer <- managed(session.createProducer(new ActiveMQQueue("Demo.Queue")))) { 32 | 33 | println("Starting to produce") 34 | for (i <- 1 until 500) { 35 | producer.send(session.createTextMessage("message" + 1)) 36 | 37 | if (i == 1 || i % 100 == 0) 38 | println(s"send $i messages") 39 | 40 | } 41 | println("Have sent all messages") 42 | 43 | } 44 | 45 | 46 | } 47 | 48 | 49 | // receive 50 | 51 | connection.start() 52 | for (session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 53 | consumer <- managed(session.createConsumer(new ActiveMQQueue("Demo.Queue")))) { 54 | 55 | println("Starting to consume") 56 | 57 | 58 | @tailrec 59 | def receive(n: Int): Int = { 60 | Option(consumer.receive(1000)) match { 61 | case Some(m) => 62 | if ((n == 1) || (n % 100 == 0)) println(s"received $n messages") 63 | receive(n + 1) 64 | case None => println("Timed out"); n 65 | } 66 | } 67 | 68 | val receivedMessages = receive(1) 69 | println("Stopping consumption") 70 | connection.stop() 71 | println(s"Done...received $receivedMessages messages") 72 | } 73 | 74 | } 75 | broker.stop() 76 | 77 | 78 | def startBroker() = { 79 | val broker = new BrokerService 80 | 81 | val kahaDB = new KahaDBStore 82 | kahaDB.setDirectory(FileSystems.getDefault.getPath("./target", "activemq", "data").toFile) 83 | kahaDB.setJournalMaxFileLength(10240 * 100) 84 | 85 | kahaDB.setIndexWriteBatchSize(100) // small batch -> more frequent small writes 86 | kahaDB.setEnableIndexWriteAsync(true) // index write in separate thread 87 | 88 | broker.setPersistenceAdapter(kahaDB) 89 | 90 | broker.addConnector("vm://local") 91 | 92 | broker.start() 93 | broker 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /project/ActiveMQDemos.scala: -------------------------------------------------------------------------------- 1 | //import com.edc4it.sbt.activemq.SbtActiveMQ 2 | import sbt.Keys._ 3 | import sbt._ 4 | import sbtassembly.Plugin.AssemblyKeys._ 5 | import sbtassembly.Plugin._ 6 | import sbtprotobuf.{ProtobufPlugin=>PB} 7 | 8 | object ActiveMQDemos extends Build { 9 | 10 | import BuildSettings._ 11 | import Dependencies._ 12 | 13 | lazy val parent = Project(id = "activemq-demos", 14 | base = file(".")) 15 | .aggregate(jmsJNDI, requestResponse, util, failOver, compositeDestination, 16 | exclusiveConsumer, wildcards, brokerNetwork, virtualTopics, embeddedBrokers, mqtt) 17 | .settings(basicSettings: _*) 18 | 19 | lazy val util = basicSpringScalaProject("util") 20 | 21 | lazy val jmsJNDI = basicProject("jms-jndi") dependsOn util 22 | lazy val requestResponse = basicSpringScalaProject("request-response") dependsOn util 23 | 24 | lazy val brokerNetwork = basicProject("broker-network") dependsOn util 25 | .settings(javaOptions in run += "-javaagent:../lib/jolokia-jvm-1.2.2-agent.jar=port=8777,host=localhost,user=smx,password=smx", 26 | fork in run := true) 27 | lazy val wildcards = basicSpringScalaProject("wildcards") dependsOn util 28 | lazy val exclusiveConsumer = basicSpringScalaProject("exclusive-consumer") dependsOn util 29 | lazy val compositeDestination = basicSpringScalaProject("composite-destination") dependsOn util 30 | lazy val failOver = basicSpringScalaProject("fail-over").dependsOn(util) 31 | // .enablePlugins(SbtActiveMQ) // brokers configured in project's build.sbt 32 | lazy val virtualTopics = basicSpringScalaProject("virtual-topics") dependsOn util 33 | lazy val embeddedBrokers = basicSpringScalaProject("embedded-broker") 34 | .settings( 35 | libraryDependencies ++= compile(xbean, activeIO), 36 | libraryDependencies ++= compile(springDB: _*) 37 | ) 38 | .dependsOn(util) 39 | 40 | lazy val protobuf = basicProject("protobuf") 41 | .settings( 42 | PB.protobufSettings: _* 43 | ) 44 | 45 | lazy val mqtt = basicSpringScalaProject("mqtt") 46 | .settings(libraryDependencies ++= compile(mqttClient, activemq)) 47 | .dependsOn(util) 48 | 49 | lazy val fabricFailOver = basicSpringScalaProject("fabric-fail-over") 50 | .settings( 51 | libraryDependencies ++= compile(fabric: _*) 52 | ) . dependsOn(util) 53 | 54 | def basicProject(name: String) = Project(id = name, base = file(name)) 55 | .settings(basicSettings: _*) 56 | .settings(libraryDependencies ++= compile(activemq, scalaARM)) 57 | .settings(assemblySettings: _*) 58 | .settings(mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) => { 59 | case "META-INF/spring.factories" => MergeStrategy.concat 60 | case "META-INF/spring.tooling" => MergeStrategy.concat 61 | case x => old(x) 62 | } }) 63 | 64 | 65 | def basicSpringScalaProject(name: String) = basicProject(name) 66 | .settings(libraryDependencies ++= compile(springScalaJMS: _*)) 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /broker-network/src/main/scala/network/BrokerNetwork.scala: -------------------------------------------------------------------------------- 1 | 2 | package network 3 | 4 | import java.net.URI 5 | import java.nio.file.Files 6 | import javax.jms.Session 7 | 8 | import org.apache.activemq.ActiveMQConnectionFactory 9 | import org.apache.activemq.broker.BrokerService 10 | import resource._ 11 | 12 | import scala.concurrent.ExecutionContext.Implicits.global 13 | import scala.concurrent._ 14 | import scala.concurrent.duration._ 15 | 16 | 17 | case class BrokerInfo(uri : String, name: String) 18 | 19 | object BrokerNetwork extends App { 20 | 21 | 22 | val brokerInfo1 = BrokerInfo("tcp://localhost:61717", "broker1") 23 | val brokerInfo2 = BrokerInfo("tcp://localhost:61718", "broker2") 24 | val brokerInfo3 = BrokerInfo("tcp://localhost:61719", "broker3") 25 | 26 | setupBroker(brokerInfo2) 27 | setupBroker(brokerInfo3) 28 | 29 | val bridge = Some(URI.create(s"static://(${brokerInfo2.uri},${brokerInfo3.uri})")) 30 | 31 | setupBroker(brokerInfo1, bridge) 32 | 33 | consume(brokerInfo2) 34 | consume(brokerInfo3) 35 | 36 | produce(brokerInfo1) 37 | 38 | def setupBroker(brokerInfo : BrokerInfo, bridge: Option[URI] = None) { 39 | val brokerService = new BrokerService 40 | brokerService.setUseJmx(true) 41 | 42 | brokerService.addConnector(brokerInfo.uri) 43 | 44 | brokerService.setDataDirectory(Files.createTempDirectory(brokerInfo.name + "Data").toString) 45 | brokerService.setBrokerName(brokerInfo.name) 46 | // bridge.map(u => brokerService.addNetworkConnector(u)) 47 | bridge match { 48 | case Some(uri) =>brokerService.addNetworkConnector(uri) 49 | case None => println("setting up no bridge") 50 | } 51 | 52 | brokerService.start() 53 | 54 | 55 | } 56 | 57 | 58 | def produce(broker : BrokerInfo) { 59 | 60 | 61 | val factory = new ActiveMQConnectionFactory(broker.uri) 62 | for (connection <- managed(factory.createConnection()); 63 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 64 | producer <- managed(session.createProducer(null))) { 65 | 66 | val queue = session.createQueue("demoQueue") 67 | for (a <- 11 to 20) 68 | producer.send(queue, session.createTextMessage(s"message via broker1: #$a")) 69 | println(s"broker1 has sent the messages") 70 | } 71 | 72 | println(s"Stopping broker1 in 30s") 73 | Thread.sleep(30000) 74 | //brokerService.stop() 75 | println(s"Stopped broker1") 76 | 77 | } 78 | 79 | def consume(broker : BrokerInfo): Unit ={ 80 | val factory = new ActiveMQConnectionFactory(broker.uri) 81 | 82 | future { 83 | for (connection <- managed(factory.createConnection()); 84 | session <- managed(connection.createSession(false, Session.AUTO_ACKNOWLEDGE)); 85 | consumer <- managed(session.createConsumer(session.createQueue("demoQueue")))) { 86 | 87 | 88 | println(s"${broker.name} is listening (10 sec time/out)") 89 | connection.start() 90 | 91 | 92 | demo.Helper.receiveText(consumer, 10 seconds) { 93 | m => println(s"queue on ${broker.name} received ${m.getText}") 94 | } 95 | 96 | } 97 | //brokerService.stop() 98 | } 99 | } 100 | 101 | 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /fail-over/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | com.edc4it 8 | fail-over 9 | pom 10 | 11 | 12 | 5.10.0 13 | 14 | 15 | 16 | 17 | repository.springsource.milestone 18 | SpringSource Milestone Repository 19 | http://repo.springsource.org/milestone 20 | 21 | 22 | fusesource 23 | FuseSource Release Repository 24 | http://repo.fusesource.com/maven2/ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | broker 33 | 34 | 35 | 36 | 37 | org.apache.activemq.tooling 38 | activemq-maven-plugin 39 | ${activemq.version} 40 | 41 | 42 | 43 | 44 | run 45 | 46 | 47 | 48 | 49 | 50 | xbean:file:./src/main/etc/activemq-broker${broker.name}.xml 51 | false 52 | 53 | 54 | org.apache.activemq.default.directory.prefix 55 | ./target/activemq 56 | 57 | 58 | 59 | 60 | 61 | org.springframework 62 | spring 63 | 2.5.5 64 | 65 | 66 | org.slf4j 67 | slf4j-log4j12 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.activemq 81 | activemq-all 82 | ${activemq.version} 83 | 84 | 85 | org.slf4j 86 | slf4j-api 87 | 1.7.6 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /websockets/js/demo.js: -------------------------------------------------------------------------------- 1 | var STOMP = (function () { 2 | 'use strict'; 3 | 4 | /** 5 | * Creates the Demo Stomp API 6 | * @param {String} url the WebSocket url 7 | * @constructor 8 | */ 9 | function DemoClient(url) { 10 | this.url = url; 11 | this.socket = null; 12 | this.messageCallback = null; 13 | } 14 | 15 | /** 16 | * Connect to the web socket and to the broker 17 | * (sends the CONNECT frame) 18 | * @param {function} callback function called when connected to the broker 19 | */ 20 | DemoClient.prototype.connect = function (callback) { 21 | var _this = this; 22 | this.socket = new WebSocket(this.url); 23 | 24 | this.socket.onopen = function () { 25 | //callback() 26 | window.console.log("WebSocket is open"); 27 | 28 | _this.socket.send(_this._marshall("CONNECT", { 29 | "accept-version": "1.2", 30 | host: "localhost", 31 | login: "admin", 32 | passcode: "admin" 33 | })); 34 | }; 35 | 36 | this.socket.onerror = function (error) { 37 | window.console.log('WebSocket Error ' + error); 38 | }; 39 | 40 | this.socket.onmessage = function (e) { 41 | window.console.log(e); 42 | if (e.data.indexOf("CONNECTED") === 0) { 43 | if (typeof callback === "function") { 44 | callback(); 45 | } 46 | } 47 | if (typeof _this.messageCallback === "function") { 48 | if (e.data.indexOf("MESSAGE") === 0) { 49 | _this.messageCallback(e.data); 50 | 51 | } 52 | } 53 | }; 54 | 55 | }; 56 | 57 | /** 58 | * Disconnect from the broker 59 | * (sends the DISCONNECT frame) 60 | * @param {function} [callback] called when disconnected 61 | */ 62 | DemoClient.prototype.disconnect = function (callback) { 63 | if (this.socket === null) { 64 | return; 65 | } 66 | this.socket.send(this._marshall("DISCONNECT")); 67 | 68 | 69 | if (typeof callback === "function") { 70 | callback(); 71 | } 72 | 73 | }; 74 | 75 | /** 76 | * Subscribe to a destination 77 | * (sends the SUBSCRIBE frame) 78 | * @param {String} destination to physical name of the destination (topic or queue) 79 | * @param {function} [callback] function called when messages arrive 80 | */ 81 | DemoClient.prototype.subscribe = function (destination, callback) { 82 | window.console.log("subscribing"); 83 | if (this.socket === null) { 84 | return; 85 | } 86 | this.socket.send(this._marshall("SUBSCRIBE", { 87 | id: "1", 88 | destination: destination, 89 | ack: "auto" 90 | })); 91 | this.messageCallback = callback; 92 | 93 | }; 94 | 95 | /** 96 | * Helper method to marshall a STOMP request 97 | * @param {String} command The command (e.g, CONNECT, ACK, DISCONNECT etc.) 98 | * @param {Object} [header] Header values to be send as part of the frame 99 | * @param {String} [body] Body to send 100 | * @returns {string} The marshaled STOMP request 101 | * @private 102 | */ 103 | DemoClient.prototype._marshall = function (command, header, body) { 104 | 105 | var frame = [command]; 106 | if (header !== undefined) { 107 | for (var name in header) { 108 | if (header.hasOwnProperty(name)) { 109 | frame.push("" + name + ":" + header[name]); 110 | } 111 | } 112 | } 113 | if (command !== "CONNECT") { 114 | frame.push("receipt:"); 115 | } 116 | 117 | frame.push('\n'); 118 | if (body !== undefined) { 119 | frame.push(body); 120 | } 121 | frame.push('\x00'); 122 | return frame.join('\n'); 123 | }; 124 | 125 | return {DemoClient: DemoClient}; // export from namespace 126 | }()); -------------------------------------------------------------------------------- /stomp-telnet/README.md: -------------------------------------------------------------------------------- 1 | # STOMP 1.2 / ActiveMQ 2 | 3 | This is a small tutorial explaining the use of [STOMP 1.2](http://stomp.github.io/stomp-specification-1.2.html) using telnet 4 | 5 | ## Setup 6 | 7 | This tutorial is based on ActiveMQ 5.10. You can download a standalone version [http://activemq.apache.org/activemq-5100-release.html](http://activemq.apache.org/activemq-5100-release.html). 8 | 9 | The stomp connector is enabled out-of-the-box. Should you however be using a different version (e.g, Fuse or Karaf based) then ensure 10 | the following connector is enabled in the `activemq.xml` configuration file 11 | ```xml 12 | 13 | ``` 14 | 15 | Start the activemq broker (we are starting the broker in the foreground , which is easy during testing and development) 16 | 17 | ```bash 18 | $ cd apache-activemq-5.10.0 19 | $ bin/activemq console 20 | ``` 21 | 22 | The tutorial below uses the hawtio console. When using activemq in standalone mode it is best you 23 | use the chrome plugin to connect to your broker: 24 | 25 | There is an excellent blog entry explaining how to connect: [http://sensatic.net/activemq/activemq-and-hawtio.html](http://sensatic.net/activemq/activemq-and-hawtio.html) 26 | 27 | ## Publish messages using STOMP 28 | 29 | ### Connect 30 | 31 | ``` 32 | telnet 33 | telnet> open localhost 61613 34 | Trying 127.0.0.1... 35 | Connected to localhost. 36 | Escape character is '^]'. 37 | ``` 38 | Some information on the protocol (from [wikipedia](http://en.wikipedia.org/wiki/Streaming_Text_Oriented_Messaging_Protocol)): 39 | > Communication between client and server is through a "frame" consisting of a number of lines. 40 | The first line contains the command, followed by headers in the form : (one per line), 41 | followed by a blank line and then the body content, ending in a null character. Communication between server and client is through a MESSAGE, 42 | RECEIPT or ERROR frame with a similar format of headers and body content. 43 | 44 | **Note**: The null character null character `^@` can be send to a linux terminal using `ctrl+@` (don't forget to use the shift) 45 | 46 | In the hawtio console you should be able to see the connection (`remoteAddress` child under `clientConnectors>stomp`) 47 | 48 | ### Next start a session 49 | 50 | The frame below initiates the session The `accept-version` and `host` headers are mandatory for STOMP 1.2 clients. 51 | 52 | ``` 53 | CONNECT 54 | accept-version:1.2 55 | host:localhost 56 | login:admin 57 | passcode:admin 58 | 59 | ^@ 60 | CONNECTED 61 | heart-beat:0,0 62 | session:ID:hp-8570w-56234-1388604777495-2:1 63 | server:ActiveMQ/5.10.0 64 | version:1.2 65 | ``` 66 | 67 | The hawtio console will now also show the client session 68 | 69 | Now that we have a session, we can use the following client frames 70 | 71 | - `SEND` - sends a message to a destination 72 | - `SUBSCRIBE` - subscribe to a destination 73 | - `UNSUBSCRIBE` - unsubscribe from a destination 74 | - `BEGIN` - starts a transaction 75 | - `COMMIT` - commits the transaction 76 | - `ABORT` - rollback the transaction 77 | - `ACK` - acknowledge of a message 78 | - `NACK` - tell server we did not consume the message 79 | - `DISCONNECT` - disconnect (always use the `receipt` header) 80 | 81 | The server will respond with one of the following frames 82 | 83 | - `MESSAGE` - message received by a subscriber 84 | - `RECEIPT` - a response indicating successful receipt of the frame sent by the client 85 | - `ERROR` - indicates something went wrong 86 | 87 | ### Send a message 88 | 89 | Below is an example [SEND](http://stomp.github.io/stomp-specification-1.2.html#SEND) frame. It uses the [Header receipt](http://stomp.github.io/stomp-specification-1.2.html). This 90 | makes it easier to see the successful reception of the frame. The example send command below 91 | also has the recommended [content-type](http://stomp.github.io/stomp-specification-1.2.html#Header_content-type) header (note the) 92 | 93 | ``` 94 | SEND 95 | destination:SomeQueue 96 | content-type:text/plain 97 | receipt:123 98 | 99 | hello^@ 100 | RECEIPT 101 | receipt-id:123 102 | ``` 103 | 104 | Consult the hawtio console and observe the message has been delivered 105 | 106 | ### disconnect 107 | 108 | The frame below disconnects from the server 109 | 110 | ``` 111 | DISCONNECT 112 | receipt:789 113 | 114 | ^@ 115 | 116 | RECEIPT 117 | receipt-id: 118 | 119 | 120 | Connection closed by foreign host. 121 | ``` 122 | 123 | ## Consume message using STOMP 124 | 125 | Start a telnet a new telnet session and connect to the broker as before. 126 | 127 | ### Subscribe to a destination 128 | 129 | The frame below subscribes to the `SomeQueue` destination. You need to pass 130 | the [id](http://stomp.github.io/stomp-specification-1.2.html#SUBSCRIBE_id_Header) header 131 | as we could have multiple open subscriptions in one session (this `id` is now indicated on each message which we receive) 132 | 133 | ``` 134 | SUBSCRIBE 135 | id:0 136 | destination:SomeQueue 137 | ack:client 138 | 139 | ^@ 140 | ``` 141 | 142 | You will immediately receive messages which were already on the queue. If you would go 143 | into hawtio and send a message, you will also receive that message instantly in the telnet STOMP session. 144 | 145 | We are using `client` (acknowledgement)[http://stomp.github.io/stomp-specification-1.2.html#SUBSCRIBE_ack_Header], 146 | other options are `client` and `client-individual`. Using `client` acknowledgement allows us to explicitly send `ACK` or `NACK` frames to indicate whether we want to acknowledge the receipt of the dispatched messages . 147 | 148 | Make sure you look at the hawtio console and notice how messages are dispatched but not yet dequeued. 149 | 150 | ### Acknowledge messages 151 | 152 | A received MESSAGE frame might look like: 153 | 154 | ``` 155 | MESSAGE 156 | ack:ID\chp-8570w-60528-1388615318930-10\c1 157 | message-id:ID\chp-8570w-60528-1388615318930-6\c1\c1\c1\c1 158 | destination:/queue/SomeQueue 159 | timestamp:1388615697080 160 | expires:0 161 | subscription:0 162 | persistent:true 163 | priority:0 164 | 165 | hello 166 | ``` 167 | 168 | Notice the inclusion of the `ack` header. This header is used for the acknowledgement and is sent when using `client` and `client-individual` acknowledgement modes. 169 | 170 | To acknowledge all the received messages use the following frame 171 | 172 | ``` 173 | ACK 174 | id:ID\chp-8570w-60528-1388615318930-10\c1 175 | subscription:0 176 | 177 | ^@ 178 | ``` 179 | 180 | This ACK frame is a *cumulative acknowledgment*, meaning all received messages are acknowledged. This is also standard behaviour when using Java JMS. 181 | Using an acknowledge mode of `client-individual` allows you to acknowledge individual messages. Also note 182 | you have to pass the `subscription` header. This is because acknowledgement id's could be equal between multiple subscriptions in a single session. 183 | 184 | GO ahead an notice the changes to the queue using the hawtio console. 185 | 186 | ### Unsubscribe 187 | 188 | To unsubscribe you just send a UNSUBSCRIBE frame containing the subscription value 189 | 190 | ``` 191 | UNSUBSCRIBE 192 | id:0 193 | receipt: 194 | 195 | ^@ 196 | ``` 197 | 198 | You can now disconnect as before. 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /websockets/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('