├── .gitignore ├── CONTRIBUTING.md ├── PLAN.md ├── README.md ├── demos ├── .gitkeep └── broker │ ├── README.md │ ├── addressing │ ├── .send-anycast.py.swp │ ├── README.md │ ├── pom.xml │ ├── resources │ │ └── UpperCaseTransformer.class │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── workshop │ │ │ └── amq7 │ │ │ └── addressing │ │ │ ├── JMSQueueReceiver.java │ │ │ ├── JMSQueueReceiverAutoCreate.java │ │ │ ├── JMSQueueSender.java │ │ │ └── JMSSubscriptions.java │ │ └── resources │ │ └── jndi.properties │ ├── advanced-features │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── workshop │ │ │ └── amq7 │ │ │ └── advancedfeatures │ │ │ └── LVQ.java │ │ └── resources │ │ └── jndi.properties │ ├── broker-protection │ └── README.md │ ├── clustering │ ├── README.md │ └── etc │ │ └── diagram.png │ ├── high-availability │ ├── README.md │ ├── etc │ │ └── backup.png │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── workshop │ │ │ └── amq7 │ │ │ └── ha │ │ │ ├── QpidSender.java │ │ │ ├── Receiver.java │ │ │ └── Sender.java │ │ └── resources │ │ └── jndi.properties │ ├── large-messages │ ├── README.md │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── redhat │ │ │ └── workshop │ │ │ └── amq7 │ │ │ ├── largemessage │ │ │ ├── Receiver.java │ │ │ └── Sender.java │ │ │ └── streammessage │ │ │ ├── Receiver.java │ │ │ └── Sender.java │ │ └── resources │ │ └── jndi.properties │ ├── pom.xml │ └── security │ └── README.md ├── dockerfiles ├── interconnnect │ └── Dockerfile └── qdr │ └── Dockerfile ├── labs ├── .gitkeep ├── 00-install-broker.md ├── 10-configure-broker.md ├── 100-brokerless.md ├── 110-enmasse.md ├── 20-clients.md ├── 30-produce-consume.md ├── 40-master-slave.md ├── 50-replication.md ├── 60-clustering.md ├── 70-admin.md ├── 75-security.md ├── 80-install-qdr.md ├── 90-broker-to-router.md ├── README.md ├── SUMMARY.md ├── book.json ├── images │ ├── .gitkeep │ ├── broker-to-router │ │ └── helloworldaddress.png │ ├── client │ │ ├── download-jms-client.png │ │ └── download-node-client.png │ ├── configuration │ │ └── startup.png │ ├── install │ │ └── downloadbroker.png │ └── produce-consume │ │ ├── consume-50.png │ │ ├── consumer-drain.png │ │ ├── dlq.png │ │ └── producer-message-count.png ├── package.json ├── publish-labs.sh └── qdr │ ├── brokerless │ ├── receiver_router3.sh │ ├── router1.conf │ ├── router2.conf │ ├── router3.conf │ ├── sender_router1.sh │ ├── start.sh │ └── stop.sh │ └── conf │ └── router-to-broker.conf ├── slides ├── .gitkeep ├── AMQ-Deepdive-Slides.pptx └── IntroducingJBossAMQ7.pptx └── usecases ├── banking-service └── README.md ├── call-center └── README.md ├── healthcare-institution └── README.md ├── online-retail └── README.md ├── telecom-service-provider └── README.md └── transportation-ticket-service └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | rpms 3 | .DS_Store 4 | .idea 5 | *.iml 6 | *.log 7 | .classpath 8 | .project 9 | .settings 10 | labs/_book 11 | labs/book.pdf 12 | labs/node_modules 13 | 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Guidelines for contributing 2 | 3 | We gladly accept contributions to the AMQ 7 workshop material! 4 | 5 | Here's some more detail about the source material for the workshop: 6 | 7 | -------------------------------------------------------------------------------- /PLAN.md: -------------------------------------------------------------------------------- 1 | # Proposed plan of action 2 | 3 | Create a hands-on workshop on multiple technical labs that anyone can walk through 4 | to get started with A-MQ v7 and explore common use cases. Each lab should be independent 5 | (only assume a vanila product install as documented in first lab) so that participant can 6 | jump to the lab topic most important to them. All code and guides (Markdown) should be stored 7 | within this Github repo. 8 | 9 | In top level README, create quick overview of how to use this lab 10 | 11 | * Lab 1 - download and install A-MQ 7, and any instructions on setting up IDE 12 | * Lab 2+ - independent lab (assumon only lab 1) on simple to more advanced A-MQ use case topics 13 | 14 | Any code needed for labs should be stored in this repo in Maven project format. 15 | 16 | Labs should include cut and paste-able code and configuration information to allow for completion. 17 | 18 | Each lab should contain in Markdown format 19 | * Overview summary of what topic will be covered in this lab 20 | * Assumptions and Pre-requistes needed before starting this lab 21 | * Step by Step instructions to complete the lab 22 | * Review of what the lab showed the participant 23 | * Where to find more information - links 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Workshop 2 | 3 | 4 | This workshop introduces participants to JBoss AMQ 7 through a presentation and hands-on lab format. The workshop is intended to be delivered in person, but will provide enough guidance for self-paced consumption. 5 | 6 | ## Agenda 7 | 8 | A rough agenda for the workshop looks like this: 9 | 10 | * High-level overview of messaging landscape 11 | * Why messaging 12 | * How it's important to cloud-native applications 13 | * JMS 14 | * AMQP 15 | * Kafka-like messaging 16 | * Messaging as a Service 17 | 18 | * Why AMQ 7 19 | * Strategic direction of AMQ 7 20 | * Use cases 21 | * High-level functionality/features 22 | 23 | * Quick intro demo (sending messages with various types of clients) 24 | 25 | * AMQ 7 broker installation and hello world (Lab 0) 26 | 27 | * Deep Dive AMQ 7 broker 28 | * Architecture 29 | * Broker 30 | * Configuration 31 | * Clients 32 | * Persistence 33 | * Clustering 34 | * Discovery 35 | * AMQP 36 | * High availability 37 | * Scaling 38 | * Complex routing 39 | * Management and Monitoring 40 | * Security 41 | 42 | * Quick intermediate demo (HA/Failover) 43 | 44 | * Deep Dive AMQ 7 Interconnect router 45 | * What is Interconnect router? 46 | * Routing 47 | * End to end delivery settlement 48 | * Smart/adaptive routing 49 | * Topologies 50 | * Configuration 51 | * Broker + Router 52 | 53 | * AMQ 7 Interconnect router demo 54 | 55 | * Hands-on Labs 56 | 57 | ## Slides 58 | 59 | The slides are written in [RevealJS](http://lab.hakim.se/reveal-js/#/)/[Hyla](https://github.com/cmoulliard/hyla) which is basically a text (asciidoc) format and then converted into an HTML 5 slideshow presentation. 60 | 61 | * [Technical slide deck for AMQ-7 broker + interconnect](http://bit.ly/amq-tech-slides) 62 | * [High-level overview of messaging landscape](slides/landscape.md) 63 | * [Why AMQ 7](slides/why-amq7.md) 64 | * [Deep Dive AMQ 7 broker](slides/deep-dive-broker.md) 65 | * [Deep Dive AMQ 7 interconnect router](slides/deep-dive-qdr.md) 66 | 67 | ## Labs 68 | 69 | The labs are written in [Gitbook](https://www.gitbook.com) format and can be viewed online or in offline book (pdf, epub, mobi) format. 70 | 71 | See the latest [lab guide](https://redhatworkshops.github.io/amqv7-workshop/index.html) for the lab table of contents; 72 | 73 | ## Usecases 74 | The use cases are expanded deliverables based on the Summit presentation by Christina Lin and cover the following use cases. 75 | 76 | Trello Project Tracking Link —> https://trello.com/b/NOUVUMcF/a-mq7-delivery-workshop-development 77 | * [Usecase 01] Telecom Service Provider Topology 78 | * [Usecase 02] Banking Service Topology 79 | * [Usecase 03] Healthcare Institution Topology 80 | * [Usecase 04] Call Center Topology 81 | * [Usecase 05] Transportation Ticketing Service Topology 82 | * [Usecase 06] Online Retail Service Toplology 83 | 84 | ## Contributing 85 | 86 | We welcome all forms of contribution (content, issues/bugs, feedback). Please see the [Contribution guidelines for ways to help](./CONTRIBUTING.md) 87 | -------------------------------------------------------------------------------- /demos/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/demos/.gitkeep -------------------------------------------------------------------------------- /demos/broker/README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | ## Install prerequisites 3 | 4 | JDK 1.8 5 | 6 | OpenJDK on Fedora 7 | 8 | yum install java-1.8.0-openjdk-devel 9 | yun install java-1.8.0-openjdk 10 | 11 | Oracle JDK with Mac 12 | 13 | http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 14 | 15 | Fedora 16 | 17 | yum install git on Fedora 18 | 19 | Mac 20 | follow instructions at https://git-scm.com/book/en/v2/Getting-Started-Installing-Git 21 | 22 | 23 | LibAIO (optional Fedora only) - Fedora - 'yum install libaio' 24 | 25 | ### Install Broker 26 | 27 | Download the latest version of the Broker from https://developers.redhat.com/products/amq/download/. 28 | 29 | Follow the install instructions at https://developers.redhat.com/products/amq/hello-world and create and run an AMQ 7 Broker 30 | instance. 31 | 32 | Goto http://localhost:8161/hawtio/login and log in using the default user/pass you created when the A-MQ7 instance was created. 33 | 34 | ### Using a Queue 35 | 36 | - Stop the Broker 37 | - Add an anycast type address with a queue 38 | ```xml 39 | 40 |
41 | 42 | 43 | 44 |
45 |
46 | ``` 47 | 48 | - Start The broker 49 | - Use the Artemis CLI to listen for some messages 50 | ```code 51 | ARTEMIS_HOME/bin/artemis consumer --destination queue://exampleQueue 52 | ``` 53 | - then send some messages with the CLI 54 | ```code 55 | ARTEMIS_HOME/bin/artemis producer --destination queue://exampleQueue 56 | ``` 57 | ### Using a topic 58 | 59 | - Stop the Broker 60 | - Add a multicast type address with a topic 61 | ```xml 62 | 63 |
64 | 65 |
66 |
67 | ``` 68 | 69 | - Start The broker 70 | 71 | - listen for some messages 72 | 73 | ```code 74 | ARTEMIS_HOME/bin/artemis consumer --destination topic://exampleTopic 75 | ``` 76 | 77 | - send some messages 78 | 79 | ```code 80 | ARTEMIS_HOME/bin/artemis producer --destination topic://exampleTopic 81 | ``` 82 | 83 | 84 | -------------------------------------------------------------------------------- /demos/broker/addressing/.send-anycast.py.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/demos/broker/addressing/.send-anycast.py.swp -------------------------------------------------------------------------------- /demos/broker/addressing/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | 25 | com.redhat.workshop.amq 26 | broker-demos 27 | 1.0.0 28 | 29 | 30 | addressing 31 | 1.0.0 32 | jar 33 | AMQ 7 JMS Addressing Model Example 34 | 35 | 36 | 37 | org.apache.geronimo.specs 38 | geronimo-jms_2.0_spec 39 | 40 | 41 | org.apache.activemq 42 | artemis-commons 43 | 44 | 45 | org.apache.qpid 46 | qpid-jms-client 47 | 48 | 49 | 50 | 51 | 52 | JMSQueueReceiver 53 | 54 | 55 | 56 | org.codehaus.mojo 57 | exec-maven-plugin 58 | 1.1 59 | 60 | 61 | verify 62 | 63 | java 64 | 65 | 66 | 67 | 68 | com.redhat.workshop.amq7.addressing.JMSQueueReceiver 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | JMSQueueSender 77 | 78 | 79 | 80 | org.codehaus.mojo 81 | exec-maven-plugin 82 | 1.1 83 | 84 | 85 | verify 86 | 87 | java 88 | 89 | 90 | 91 | 92 | com.redhat.workshop.amq7.addressing.JMSQueueSender 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | JMSQueueReceiverAutoCreate 101 | 102 | 103 | 104 | org.codehaus.mojo 105 | exec-maven-plugin 106 | 1.1 107 | 108 | 109 | verify 110 | 111 | java 112 | 113 | 114 | 115 | 116 | com.redhat.workshop.amq7.addressing.JMSQueueReceiverAutoCreate 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | JMSSubscriptions 125 | 126 | 127 | 128 | org.codehaus.mojo 129 | exec-maven-plugin 130 | 1.1 131 | 132 | 133 | verify 134 | 135 | java 136 | 137 | 138 | 139 | 140 | com.redhat.workshop.amq7.addressing.JMSSubscriptions 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /demos/broker/addressing/resources/UpperCaseTransformer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/demos/broker/addressing/resources/UpperCaseTransformer.class -------------------------------------------------------------------------------- /demos/broker/addressing/src/main/java/com/redhat/workshop/amq7/addressing/JMSQueueReceiver.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.addressing; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.MessageConsumer; 22 | import javax.jms.MessageProducer; 23 | import javax.jms.Queue; 24 | import javax.jms.Session; 25 | import javax.jms.TextMessage; 26 | import javax.naming.InitialContext; 27 | 28 | public class JMSQueueReceiver { 29 | 30 | public static void main(String args[]) throws Exception { 31 | 32 | try { 33 | InitialContext context = new InitialContext(); 34 | 35 | Queue queue = (Queue) context.lookup("orders"); 36 | 37 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 38 | 39 | try (Connection connection = cf.createConnection()) { 40 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 41 | MessageConsumer consumer = session.createConsumer(queue); 42 | 43 | connection.start(); 44 | 45 | System.out.println("==========================="); 46 | System.out.println("Receiving Messages"); 47 | while (true) { 48 | TextMessage message = (TextMessage) consumer.receive(1000); 49 | if (message != null) { 50 | System.out.println("Received Message: " + message); 51 | } 52 | } 53 | } 54 | } catch (Exception e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /demos/broker/addressing/src/main/java/com/redhat/workshop/amq7/addressing/JMSQueueReceiverAutoCreate.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.addressing; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.MessageConsumer; 22 | import javax.jms.Queue; 23 | import javax.jms.Session; 24 | import javax.jms.TextMessage; 25 | import javax.naming.InitialContext; 26 | 27 | public class JMSQueueReceiverAutoCreate { 28 | 29 | public static void main(String args[]) throws Exception { 30 | 31 | try { 32 | InitialContext context = new InitialContext(); 33 | 34 | Queue queue = (Queue) context.lookup("auto.created"); 35 | 36 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 37 | 38 | try (Connection connection = cf.createConnection()) { 39 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 40 | MessageConsumer consumer = session.createConsumer(queue); 41 | 42 | connection.start(); 43 | 44 | System.out.println("==========================="); 45 | System.out.println("Receiving Messages"); 46 | while (true) { 47 | TextMessage message = (TextMessage) consumer.receive(1000); 48 | if (message != null) { 49 | System.out.println("Received Message: " + message); 50 | } 51 | } 52 | } 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /demos/broker/addressing/src/main/java/com/redhat/workshop/amq7/addressing/JMSQueueSender.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.addressing; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.Message; 22 | import javax.jms.MessageConsumer; 23 | import javax.jms.MessageProducer; 24 | import javax.jms.Queue; 25 | import javax.jms.Session; 26 | import javax.naming.InitialContext; 27 | 28 | public class JMSQueueSender { 29 | 30 | public static void main(String args[]) throws Exception { 31 | 32 | try { 33 | InitialContext context = new InitialContext(); 34 | 35 | Queue queue = (Queue) context.lookup("orders"); 36 | 37 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 38 | 39 | try (Connection connection = cf.createConnection()) { 40 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 41 | MessageProducer producer = session.createProducer(queue); 42 | 43 | connection.start(); 44 | 45 | for (int i = 0; i < 10; i++) { 46 | producer.send(session.createTextMessage("Test Message")); 47 | } 48 | } 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /demos/broker/addressing/src/main/java/com/redhat/workshop/amq7/addressing/JMSSubscriptions.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.addressing; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.Message; 22 | import javax.jms.MessageConsumer; 23 | import javax.jms.Session; 24 | import javax.jms.Topic; 25 | import javax.naming.InitialContext; 26 | import java.util.UUID; 27 | 28 | public class JMSSubscriptions { 29 | 30 | public static void main(String args[]) throws Exception { 31 | 32 | try { 33 | InitialContext context = new InitialContext(); 34 | 35 | Topic volatileSubscription = (Topic) context.lookup("volatileSubscription"); 36 | Topic durableSubscription = (Topic) context.lookup("durableSubscription"); 37 | Topic sharedVolatileSubscription = (Topic) context.lookup("sharedVolatileSubscription"); 38 | Topic sharedDurableSubscription = (Topic) context.lookup("sharedDurableSubscription"); 39 | 40 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 41 | 42 | try (Connection connection = cf.createConnection()) { 43 | connection.setClientID("ThisIsTheClientID"); 44 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 45 | 46 | // Create volatile subscription 47 | MessageConsumer volatileSubcriber = session.createConsumer(volatileSubscription); 48 | MessageConsumer durableSubcriber = session.createDurableSubscriber(durableSubscription, "durableSubName"); 49 | MessageConsumer volatileSharedSubcriber = session.createSharedConsumer(sharedVolatileSubscription, "sharedVolatileSubName"); 50 | MessageConsumer durableSharedSubcriber = session.createSharedDurableConsumer(sharedDurableSubscription, "sharedDurableSubName"); 51 | 52 | System.out.println("========================"); 53 | System.out.println(" Created JMS Subscriptions"); 54 | System.out.println("========================"); 55 | 56 | while(true) { 57 | Message m = null; 58 | m = volatileSubcriber.receiveNoWait(); 59 | if (m != null) { 60 | System.out.println("Volatile Subscriber: " + m); 61 | m = null; 62 | } 63 | 64 | m = durableSubcriber.receiveNoWait(); 65 | if (m != null) { 66 | System.out.println("Durable Subscriber: " + m); 67 | m = null; 68 | } 69 | 70 | m = volatileSharedSubcriber.receiveNoWait(); 71 | if (m != null) { 72 | System.out.println("Shared Volatile Subscriber: " + m); 73 | m = null; 74 | } 75 | 76 | m = durableSharedSubcriber.receiveNoWait(); 77 | if (m != null) { 78 | System.out.println("Shared Durable Subscriber: " + m); 79 | m = null; 80 | } 81 | 82 | } 83 | } 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /demos/broker/addressing/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory 2 | connectionFactory.ConnectionFactory=amqp://localhost:5672 3 | queue.orders=orders 4 | queue.auto.created=auto.created 5 | topic.volatileSubscription=volatileSubscription 6 | topic.durableSubscription=durableSubscription 7 | topic.sharedVolatileSubscription=sharedVolatileSubscription 8 | topic.sharedDurableSubscription=sharedDurableSubscription -------------------------------------------------------------------------------- /demos/broker/advanced-features/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Features in AMQ 7 broker 2 | 3 | This worksheet covers some advanced features in the AMQ 7 broker. By the end of this worksheet you should know: 4 | 5 | 1. How a "last-value" queue works 6 | 2. How to configure a dead-letter address 7 | 3. How slow-consumer detection works 8 | 9 | ## Last-Value Queues 10 | 11 | A Last-Value queue (henceforth LVQ) is a special queue which discards any messages when a newer message with the same value for a well-defined Last-Value property (i.e. `_AMQ_LVQ_NAME`) is put in the queue. In other words, an LVQ queue only retains the last value. 12 | 13 | This functionality is configured via the `` element specified in a matching ``. For example, given this address & queue: 14 | 15 | ```xml 16 | 17 |
18 | 19 | 20 | 21 |
22 |
23 | ``` 24 | 25 | This `` would enable LVQ semantics: 26 | 27 | ```xml 28 | 29 | true 30 | 31 | ``` 32 | 33 | Add this address & queue to your broker.xml (but not the ``). 34 | 35 | Now run the LVQ example to send 3 messages which have the same value for `_AMQ_LVQ_NAME`: 36 | 37 | ``` 38 | mvn verify -PLVQ 39 | ``` 40 | 41 | Now consume those messages: 42 | 43 | ``` 44 | $ /bin/artemis consumer --destination lastValueQueue --receive-timeout 1000 --break-on-null 45 | ``` 46 | 47 | Three messages will be consumed. 48 | 49 | Now we want to enable LVQ semantics on the queue we created. However, because the runtime configuration logic only supports non-destructive changes we have to stop the broker and clear the journal using this command: 50 | 51 | ```sh 52 | rm -Rf AMQ_INSTANCE/data/ 53 | ``` 54 | 55 | Then add the aforementioned `` to broker.xml, start the broker, and run the sender again: 56 | 57 | ``` 58 | mvn verify -PLVQ 59 | ``` 60 | 61 | Now consume those messages: 62 | 63 | ``` 64 | $ /bin/artemis consumer --destination lastValueQueue --receive-timeout 1000 --break-on-null 65 | ``` 66 | 67 | Only 1 message (the last one - #3) will be consumed. 68 | 69 | It's important to note that LVQ is not currently supported for AMQP clients. 70 | 71 | ## Dead-letter address 72 | 73 | A "dead-letter" destination is a common concept in messaging. Simply put, it's a place where messages are sent when a client fails to consume them. In AMQ 7 this behavior is configured via ``. 74 | 75 | Here is one of the default `` elements: 76 | 77 | ```xml 78 | 79 | DLQ 80 | ExpiryQueue 81 | 0 82 | 83 | -1 84 | 10 85 | PAGE 86 | true 87 | true 88 | true 89 | true 90 | 91 | ``` 92 | 93 | Notice the `` attribute. It tells the broker where to send messages which clients fail to consume. Other related attributes are: 94 | 95 | * **max-delivery-attempts** How many time a cancelled message can be redelivered before sending to the dead-letter-address. 96 | * **redelivery-delay** How long to wait before attempting redelivery of a cancelled message. 97 | * **redelivery-delay-multiplier** This multiplier enables subsequent redelivery delays to be larger. The formula used here is (redlivery-delay * (redlivery-delay-multiplier ^ (delivery-count - 1))). 98 | * **max-redelivery-delay** Sets are hard limit on the maximum redelivery delay which may be useful when using `redelivery-delay-multiplier` and a large `max-delivery-attempts`. 99 | * **send-to-dla-on-no-route** If a message is sent to an address, but the server does not route it to any queues, for example, there might be no queues bound to that address, or none of the queues have filters that match, then normally that message would be discarded. However if this parameter is set to true for that address, if the message is not routed to any queues it will instead be sent to the dead letter address (DLA) for that address, if it exists. 100 | 101 | Here's a simple example that combines most of these attributes: 102 | 103 | ```xml 104 | 105 | DLQ 106 | 1000 107 | 2 108 | 10000 109 | 6 110 | 111 | ``` 112 | 113 | Consider a broken client who is simply unable to consume a message successfully. This broken consumer is listening to a queue which has 1 message. Here is how the sequence of delivery attempts would go given the `` above: 114 | 115 | 1. no delay on the first attempt 116 | 2. delivery-count = 1, delay of 1 second (1000 * (2.0 ^ 0)) 117 | 3. delivery-count = 2, delay of 2 seconds (1000 * (2.0 ^ 1)) 118 | 4. delivery-count = 3, delay of 4 seconds (1000 * (2.0 ^ 2)) 119 | 5. delivery-count = 4, delay of 8 seconds (1000 * (2.0 ^ 3)) 120 | 6. delivery-count = 5, delay of 10 seconds since (1000 * (2.0 ^ 4)) is > 10000 which is the max-redelivery-delay 121 | 7. delivery-count = 6, send to the dead-letter address "DLQ" 122 | 123 | ## Slow-consumer detection 124 | 125 | A slow consumer with a server-side queue (e.g. JMS topic subscriber) can pose a significant problem for broker performance. If messages build up in the consumer's server-side queue then memory will begin filling up and the broker may enter paging mode which would impact performance negatively. However, criteria can be set so that consumers which don't acknowledge messages quickly enough can potentially be disconnected from the broker which in the case of a non-durable JMS subscriber would allow the broker to remove the subscription and all of its messages freeing up valuable server resources. 126 | 127 | Slow-consumer detection is configured via the following `` attributes: 128 | 129 | * **slow-consumer-threshold** The minimum rate of message consumption allowed before a consumer is considered "slow." Measured in messages-per-second. Default is -1 (i.e. disabled); any other valid value must be greater than 0. 130 | * **slow-consumer-policy** What should happen when a slow consumer is detected. KILL will kill the consumer's connection (which will obviously impact any other client threads using that same connection). NOTIFY will send a CONSUMER_SLOW management notification which an application could receive and take action with. 131 | * **slow-consumer-check-period** How often to check for slow consumers on a particular queue. Measured in seconds. Default is 5. -------------------------------------------------------------------------------- /demos/broker/advanced-features/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | 25 | com.redhat.workshop.amq 26 | broker-demos 27 | 1.0.0 28 | 29 | 30 | advanced-features 31 | 1.0.0 32 | jar 33 | AMQ 7 Advanced Features Example 34 | 35 | 36 | 37 | org.apache.geronimo.specs 38 | geronimo-jms_2.0_spec 39 | 40 | 41 | org.apache.activemq 42 | artemis-commons 43 | 44 | 45 | org.apache.activemq 46 | artemis-jms-client 47 | 48 | 49 | 50 | 51 | 52 | LVQ 53 | 54 | 55 | 56 | org.codehaus.mojo 57 | exec-maven-plugin 58 | 1.1 59 | 60 | 61 | verify 62 | 63 | java 64 | 65 | 66 | 67 | 68 | com.redhat.workshop.amq7.advancedfeatures.LVQ 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /demos/broker/advanced-features/src/main/java/com/redhat/workshop/amq7/advancedfeatures/LVQ.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.advancedfeatures; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.Message; 22 | import javax.jms.MessageConsumer; 23 | import javax.jms.MessageProducer; 24 | import javax.jms.Queue; 25 | import javax.jms.Session; 26 | import javax.naming.InitialContext; 27 | 28 | public class LVQ { 29 | 30 | public static void main(String args[]) throws Exception { 31 | 32 | try { 33 | InitialContext context = new InitialContext(); 34 | 35 | Queue queue = (Queue) context.lookup("lastValue"); 36 | 37 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 38 | 39 | try (Connection connection = cf.createConnection()) { 40 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 41 | MessageProducer producer = session.createProducer(queue); 42 | 43 | for (int i = 1; i <= 3; i++) { 44 | Message message = session.createTextMessage("Message " + i); 45 | message.setStringProperty("_AMQ_LVQ_NAME", "123"); 46 | producer.send(message); 47 | } 48 | } 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /demos/broker/advanced-features/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 2 | connectionFactory.ConnectionFactory=tcp://localhost:61616 3 | queue.lastValue=lastValue 4 | -------------------------------------------------------------------------------- /demos/broker/broker-protection/README.md: -------------------------------------------------------------------------------- 1 | # Protecting the Broker in AMQ 7 2 | 3 | This worksheet covers some broker protection features in the AMQ 7 broker. By the end of this worksheet you should know: 4 | 5 | 1. How to configure the behavior of the broker when an address becomes "full" 6 | 2. How to use resource-limit-settings to restrict how many queues and/or connections a specific user can create 7 | 3. How to configure an acceptor to limit the number of allowed TCP connections 8 | 9 | ## Address-full policies 10 | 11 | As messages accumulate in the broker there is a chance that the JVM could run out of heap space. There are several options to deal with this possibility which can be configured in a matching ``: 12 | 13 | * **max-size-bytes** How large an address can be before it's considered "full". The size of an address is calculated by summing the sizes of all the queues bound to the address. This includes durable, non-durable, statically created, and dynamically (i.e. auto) created queues. Note, this is done on a per-address basis so even though the `match` of the `` may be `#` the `max-size-bytes` applies to each individual address and not every matching address as a whole. 14 | * **address-full-policy** What to do when the address becomes full. Options are: 15 | * **PAGE** messages will be stored on disk 16 | * **DROP** messages will be silently dropped (i.e. deleted) 17 | * **FAIL** messages will be dropped and the relevant producer will receive an error 18 | * **BLOCK** relevant producer will be blocked from sending additional messages; only clients which support flow-control (i.e. core JMS, AMQP) will block 19 | 20 | Aside from the per-address limits there are also global limits: 21 | 22 | * **global-max-size** When all the message data in the broker reaches this limit then all addresses will apply their respective ``. Measured in bytes; supports byte notation (e.g. Mb, GB, kb, etc.). Defaults to Xmx/2. 23 | * **max-disk-usage** When disk utilization reaches this percentage (for any reason) then all clients supporting flow control will be blocked and those that don't will be disconnected. 24 | 25 | These are the parts of the default configuration relevant to this discussion: 26 | 27 | ```xml 28 | 90 29 | 30 | 100Mb 31 | 32 | 33 | DLQ 34 | ExpiryQueue 35 | 0 36 | 37 | -1 38 | 10 39 | PAGE 40 | true 41 | true 42 | true 43 | true 44 | 45 | ``` 46 | 47 | ### Hands on 48 | 49 | Create a fresh broker instance: 50 | 51 | ``` 52 | $ /bin/artemis create --user --password --role admin --require-login /instances/myprotectedbroker 53 | ``` 54 | 55 | Open `AMQ_INSTANCE/etc/broker.xml` and change `` as the default value (i.e. 90) can inadvertently trigger blocking if your disk is close to full: 56 | 57 | ```xml 58 | 100 59 | ``` 60 | 61 | Then change the `` for `` to: 62 | 63 | ```xml 64 | BLOCK 65 | ``` 66 | 67 | And also change the `` to: 68 | 69 | ```xml 70 | 1MB 71 | ``` 72 | 73 | Now send messages to the broker: 74 | 75 | ``` 76 | $ /bin/artemis producer --user --password --message-size 1050 77 | ``` 78 | 79 | The producer should block with this: 80 | 81 | ``` 82 | AMQ212054: Destination address=TEST is blocked. If the system is configured to block make sure you consume messages on this configuration. 83 | ``` 84 | 85 | Kill the producer (e.g. using Ctrl-C), and consume all the messages: 86 | 87 | ``` 88 | $ /bin/artemis consumer --user --password --receive-timeout 1000 --break-on-null 89 | ``` 90 | 91 | Check the AMQ 7 log and you'll see where the broker blocked and unblocked during the exercise. 92 | 93 | ## Resource limits 94 | 95 | Broker administrators may be concerned with how many connections or queues a particular user is allowed to create. This can be configured via ``, e.g.: 96 | 97 | ```xml 98 | 99 | 100 | 100 101 | 10 102 | 103 | 104 | ``` 105 | 106 | The `match` attribute on `` matches a username. Wildcards are not supported on this match. The `` is how many queues the user is allowed to create either manually or via auto-creation. The `` is how many connections the user is allowed to create. 107 | 108 | ## Hands on 109 | 110 | Add this to your `AMQ_INSTANCE/etc/broker.xml`: 111 | 112 | ```xml 113 | 114 | 115 | 0 116 | 117 | 118 | ``` 119 | 120 | Restart the broker (because `` is not automatically picked up when changed at runtime) and try to send messages: 121 | 122 | ``` 123 | $ /bin/artemis producer --user --password 124 | ``` 125 | 126 | This should fail since the producer will attempt to create the queue "TEST" by default: 127 | 128 | ``` 129 | javax.jms.JMSException: AMQ119111: Too many queues created by user ''. Queues allowed: 0. 130 | ``` 131 | 132 | Now change the ``: 133 | 134 | ```xml 135 | 136 | 137 | 10 138 | 3 139 | 140 | 141 | ``` 142 | 143 | Run a consumer with 2 threads. Note, even though there's just 2 threads the core JMS client will actually create 3 core sessions - 1 for the JMS connection and 1 each for the JMS sessions (1 per thread) for a total of 3. 144 | 145 | ``` 146 | $ /bin/artemis consumer --user --password --threads 2 --receive-timeout 100 --break-on-null 147 | ``` 148 | 149 | This will run without problems. However, a consumer with 3 threads (i.e. 4 core sessions) will fail: 150 | 151 | ``` 152 | $ /bin/artemis consumer --user --password --threads 3 --receive-timeout 100 --break-on-null 153 | ``` 154 | 155 | Here's the output: 156 | 157 | ``` 158 | javax.jms.JMSException: AMQ119110: Too many sessions for user ''. Sessions allowed: 3. 159 | ``` 160 | 161 | ## Limiting Connections on an Acceptor 162 | 163 | Instead of limiting connections on a user-by-user basis you can also apply a global limit on connections to an acceptor using the `connectionsAllowed` URL property. 164 | 165 | ### Hands on 166 | 167 | Stop your broker instance, remove the ``, and change the `artemis` acceptor to this (adding `;connectionsAllowed=1` to the end): 168 | 169 | ```xml 170 | tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;connectionsAllowed=1 171 | ``` 172 | 173 | Restart the broker and connect a consumer: 174 | 175 | ``` 176 | $ /bin/artemis consumer --user myuser --password mypass 177 | ``` 178 | 179 | This will succeed. Note, even though the consumer is creating multiple core sessions it's only using a single TCP connection. 180 | 181 | Connect another consumer: 182 | 183 | ``` 184 | $ /bin/artemis consumer --user myuser --password mypass 185 | ``` 186 | 187 | This will fail after a bit and ask you for a working URL. The broker will report something like this: 188 | 189 | ``` 190 | AMQ222206: Connection limit of 1 reached. Refusing connection from /127.0.0.1:57918 191 | ``` 192 | 193 | The broker here is simply closing the TCP connection which may result in different behavior in the different supported clients. -------------------------------------------------------------------------------- /demos/broker/clustering/README.md: -------------------------------------------------------------------------------- 1 | ## Networks of Brokers in AMQ 7 Broker (Clustering) 2 | 3 | This worksheet covers clustering AMQ 7 brokers. By the end of this you should know: 4 | 5 | 1. Clustering concepts of AMQ 7 6 | * Discovery 7 | * Cluster bridges 8 | * Routing of messages 9 | * Client side load balancing 10 | * Server side load balancing 11 | 12 | 2. How to configure Clustering 13 | * Configuring Discovery 14 | * Configuring a cluster 15 | * Configuring Load Balancing 16 | 17 | 18 | ### AMQ 7 Clustering Concepts 19 | 20 | Multiple instances of AMQ 7 brokers can be grouped together to share message processing load. 21 | Each broker manages its own messages and connections and is connected to other brokers with 22 | "cluster bridges" that are used to send topology information, such as queues and consumers, 23 | as well as load balancing messages. 24 | 25 | ### Simple 2-node cluster 26 | 27 | Lets create 2 clustered brokers using the CLI, firstly, since AMQ 7 uses UDP for discovery 28 | you will need to ensure that a loopback address is created, this will allow UDP to work on the same machine. 29 | On Linux run the following command. 30 | 31 | sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev lo 32 | 33 | On a Mac this will be something like 34 | 35 | ? find this out 36 | 37 | Now lets create a cluster of 2 brokers by running the CLI commands 38 | 39 | ``` 40 | $ /bin/artemis create --user admin --password password --role admin --allow-anonymous y --clustered --host 127.0.0.1 --cluster-user clusterUser --cluster-password clusterPassword --max-hops 1 ../instances/clusteredbroker1 41 | ``` 42 | 43 | and 44 | 45 | ``` 46 | $ /bin/artemis create --user admin --password password --role admin --allow-anonymous y --clustered --host 127.0.0.1 --cluster-user clusterUser --cluster-password clusterPassword --max-hops 1 --port-offset 100 ../instances/clusteredbroker2 47 | ``` 48 | 49 | Now start *both* brokers using the `run` command for each one, for instance: 50 | 51 | ``` 52 | $ /bin/artemis run 53 | ``` 54 | 55 | What you should see is each broker discovering each other and creating a cluster bridge. You should see a log message on each broker showing this, something like: 56 | 57 | ```bash 58 | INFO [org.apache.activemq.artemis.core.server] AMQ221027: Bridge ClusterConnectionBridge@1d90c678 [name=$.artemis.internal.sf.my-cluster.8d25b0ff-55ad-11e7-bfb2-e8b1fc559583, queue=QueueImpl[name=$.artemis.internal.sf.my-cluster.8d25b0ff-55ad-11e7-bfb2-e8b1fc559583, postOffice=PostOfficeImpl [server=ActiveMQServerImpl::serverUUID=86fab59a-55ad-11e7-ae52-e8b1fc559583], temp=false]@60ff2ab7 targetConnector=ServerLocatorImpl (identity=(Cluster-connection-bridge::ClusterConnectionBridge@1d90c678 [name=$.artemis.internal.sf.my-cluster.8d25b0ff-55ad-11e7-bfb2-e8b1fc559583, queue=QueueImpl[name=$.artemis.internal.sf.my-cluster.8d25b0ff-55ad-11e7-bfb2-e8b1fc559583, postOffice=PostOfficeImpl [server=ActiveMQServerImpl::serverUUID=86fab59a-55ad-11e7-ae52-e8b1fc559583], temp=false]@60ff2ab7 targetConnector=ServerLocatorImpl [initialConnectors=[TransportConfiguration(name=artemis, factory=org-apache-activemq-artemis-core-remoting-impl-netty-NettyConnectorFactory) ?port=61716&host=127-0-0-1], discoveryGroupConfiguration=null]]::ClusterConnectionImpl@943454742[nodeUUID=86fab59a-55ad-11e7-ae52-e8b1fc559583, connector=TransportConfiguration(name=artemis, factory=org-apache-activemq-artemis-core-remoting-impl-netty-NettyConnectorFactory) ?port=61616&host=127-0-0-1, address=, server=ActiveMQServerImpl::serverUUID=86fab59a-55ad-11e7-ae52-e8b1fc559583])) [initialConnectors=[TransportConfiguration(name=artemis, factory=org-apache-activemq-artemis-core-remoting-impl-netty-NettyConnectorFactory) ?port=61716&host=127-0-0-1], discoveryGroupConfiguration=null]] is connected 59 | ``` 60 | 61 | You can also log into the HawtIO Console by going to 'http://localhost:8161/hawtio' and click on the 62 | 'ARTEMIS' tab then the 'Diagram' tab. You will see 2 Brokers and also the Store and Forward Addresses 63 | and queues: 64 | 65 | ![alt text](etc/diagram.png "Broker Diagram") 66 | 67 | 68 | We now have a cluster of 2 brokers, lets look in more detail at the configuration. 69 | 70 | #### Discovery 71 | 72 | When a clustered broker is started the first thing it does is try to discover another broker in the cluster. 73 | It will keep doing this until it finds a broker at which time it will try to create a cluster bridge to it. 74 | By default the broker will use UDP multicast to broadcast its location and to also discover other brokers. 75 | 76 | The first thing to notice in the configuration file is the connector config that will be broadcast to other brokers, this 77 | looks like: 78 | 79 | ```xml 80 | tcp://127.0.0.1:61616 81 | ``` 82 | 83 | A `broadcast-group` then defines how a broker broadcasts the connector info, this looks something like: 84 | 85 | ```xml 86 | 87 | 231.7.7.7 88 | 9876 89 | 5000 90 | artemis 91 | 92 | 93 | ``` 94 | 95 | This configuration will broadcast the 'artemis' connector info over the multicast address 231.7.7.7:9876 every 5 secosnds. 96 | 97 | Now a broker needs to be able discover the above broadcast, this is done via a `discovery-group`. This looks like: 98 | 99 | ```xml 100 | 101 | 231.7.7.7 102 | 9876 103 | 10000 104 | 105 | ``` 106 | 107 | This configuration doesn't do anything by itself but is referenced by a `cluster-connection`, which looks like: 108 | 109 | ```xml 110 | 111 | artemis 112 | ON_DEMAND 113 | 1 114 | 115 | 116 | ``` 117 | 118 | You can see that the `discovery-group-ref` references a discovery group. Once started, the broker will listen on 119 | the multicast address 231.7.7.7:9876 for other brokers broadcasting. 120 | 121 | Once the broker has discovered a target broker it will try to create a cluster bridge to that broker. We refer to this as *initial discovery*. 122 | Once initial discovery is complete all other discovery is done over the cluster bridge itself. In a 2 node cluster it would happen 123 | like so: 124 | 125 | 1. The source broker sends its full topology over the cluster bridge to its target broker. This includes a list of brokers it 126 | is aware of (including itself configured by the `connector-ref` in the `cluster-connection`) and a list of queues and consumers. 127 | 2. The target broker then uses the list of brokers to create its own cluster bridges (in this case back to the source broker). 128 | 3. The target broker then sends its own topology over its cluster bridges. 129 | 4. Both brokers create any queues based on the topology received. 130 | 131 | 132 | ##### Discovery without UDP multicast (Static Connectors), Optional 133 | 134 | If UDP multicast is not available then brokers can be *statically* configured. This is done purely through connectors. 135 | 136 | Lets update brokers 1 and 2 to use static connectors. 137 | 138 | Firstly remove both the broadcast and discovery groups configuration completely. 139 | 140 | ```xml 141 | 142 | 143 | 144 | 231.7.7.7 145 | 9876 146 | 5000 147 | artemis 148 | 149 | 150 | 151 | 152 | 153 | 231.7.7.7 154 | 9876 155 | 10000 156 | 157 | 158 | ``` 159 | 160 | Then on each broker add a connector that points to the *other* broker. So on broker 1 it would look like: 161 | 162 | ```xml 163 | tcp://127.0.0.1:61716 164 | ``` 165 | 166 | And on broker 2 it would look like: 167 | 168 | ```xml 169 | tcp://127.0.0.1:61616 170 | ``` 171 | 172 | Lastly remove the `discovery-group-ref` from the `cluster-connection` on both brokers and replace it with the following: 173 | 174 | ```xml 175 | 176 | discovery-connector 177 | 178 | ``` 179 | 180 | Now if you restart the brokers you will again see them form a cluster. 181 | 182 | > ##### Note 183 | > The static connectors list can contain all the possible brokers in the cluster, 184 | > however it only needs 1 to be available to connect to. 185 | 186 | 187 | #### Client-side Connection Load Balancing 188 | 189 | Client-side connection load balancing is the ability of a client to spread connections across multiple brokers, 190 | currently only the core JMS client supports this. This is done via load balancing policies configured on the 191 | connection factory via the `loadBalancingPolicyClassName` URL property. If using JNDI the `jndi.properties` would look like: 192 | 193 | ```properties 194 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 195 | connection.myConnectionFactory=tcp://localhost:61616?loadBalancingPolicyClassName=org.apache.activemq.artemis.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy 196 | ``` 197 | 198 | The available policies are 199 | 200 | * Round Robin (`org.apache.activemq.artemis.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy`). 201 | * Random (`org.apache.activemq.artemis.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy`). 202 | * Random Sticky (`org.apache.activemq.artemis.api.core.client.loadbalance.RandomStickyConnectionLoadBalancingPolicy`). 203 | * First Element (`org.apache.activemq.artemis.api.core.client.loadbalance.FirstElementConnectionLoadBalancingPolicy`). 204 | 205 | All of these classes ship in the `artemis-core-client` JAR. You can also implement your own policy by implementing the `org.apache.activemq.artemis.api.core.client.loadbalance.ConnectionLoadBalancingPolicy` interface. 206 | 207 | #### Message Load Balancing 208 | 209 | The message load balancing policy configures how messages are load balanced around the cluster *by the server*. 210 | This is configured in the cluster-connection, like so. 211 | 212 | ```xml 213 | ON_DEMAND 214 | ``` 215 | 216 | By default it is ON_DEMAND, which means that messages will be round robined around Brokers that have available consumers. 217 | 218 | > ##### Note 219 | > Messages are routed at the point they arrive at the broker and before they arrive on a queue. 220 | > They will either route to a local queue or to a queue on another broker 221 | 222 | We can test this using the CLI, but firstly each broker needs to be stopped and the clustered queues configured, 223 | add the following queue to each broker: 224 | 225 | ```xml 226 |
227 | 228 | 229 | 230 |
231 | ``` 232 | 233 | And then restart the brokers. 234 | 235 | firstly lets send 20 messages to broker 1: 236 | 237 | ```bash 238 | $ /bin/artemis producer --url tcp://localhost:61616 --message-count 20 --destination queue://myQueue 239 | ``` 240 | 241 | Since there are no consumers these will simple be delivered to the local queue on broker 1. We can test this by trying 242 | to consume from broker 2: 243 | 244 | ```bash 245 | $ /bin/artemis consumer --url tcp://localhost:61716 --destination queue://myQueue --message-count 10 246 | ``` 247 | 248 | This should just hang without receiving any message. Now try broker 1 249 | 250 | ```bash 251 | $ /bin/artemis consumer --url tcp://localhost:61616 --destination queue://myQueue --message-count 20 252 | ``` 253 | 254 | The client will receive all 20 message. 255 | 256 | Now restart both receiving clients with --message-count 10 257 | 258 | They will sit there awaiting messages, now send some another 20 messages. What you see this time is the messages round robined on demand. 259 | 260 | Now try the first part of this again, but this time setting the load balancing to strict, like so: 261 | 262 | ```xml 263 | STRICT 264 | ``` 265 | 266 | This time the messages are load balanced even though no consumer exist. -------------------------------------------------------------------------------- /demos/broker/clustering/etc/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/demos/broker/clustering/etc/diagram.png -------------------------------------------------------------------------------- /demos/broker/high-availability/etc/backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/demos/broker/high-availability/etc/backup.png -------------------------------------------------------------------------------- /demos/broker/high-availability/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | 25 | com.redhat.workshop.amq 26 | broker-demos 27 | 1.0.0 28 | 29 | 30 | HAClient 31 | 1.0.0 32 | jar 33 | AMQ 7 HA Examples 34 | 35 | 36 | 37 | org.apache.geronimo.specs 38 | geronimo-jms_2.0_spec 39 | 40 | 41 | org.apache.activemq 42 | artemis-commons 43 | 44 | 45 | org.apache.activemq 46 | artemis-jms-client 47 | 48 | 49 | 50 | org.apache.qpid 51 | qpid-jms-client 52 | 53 | 54 | 55 | 56 | 57 | HAMessageSender 58 | 59 | 60 | 61 | org.codehaus.mojo 62 | exec-maven-plugin 63 | 1.1 64 | 65 | 66 | verify 67 | 68 | java 69 | 70 | 71 | 72 | 73 | com.redhat.workshop.amq7.ha.Sender 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | HAMessageReceiver 82 | 83 | 84 | 85 | org.codehaus.mojo 86 | exec-maven-plugin 87 | 1.1 88 | 89 | 90 | verify 91 | 92 | java 93 | 94 | 95 | 96 | 97 | com.redhat.workshop.amq7.ha.Receiver 98 | 99 | 100 | 101 | 102 | 103 | 104 | HAQpidMessageSender 105 | 106 | 107 | 108 | org.codehaus.mojo 109 | exec-maven-plugin 110 | 1.1 111 | 112 | 113 | verify 114 | 115 | java 116 | 117 | 118 | 119 | 120 | com.redhat.workshop.amq7.ha.QpidSender 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /demos/broker/high-availability/src/main/java/com/redhat/workshop/amq7/ha/QpidSender.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.ha; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.MessageProducer; 22 | import javax.jms.Queue; 23 | import javax.jms.Session; 24 | import javax.jms.TextMessage; 25 | import javax.jms.TransactionRolledBackException; 26 | import javax.naming.InitialContext; 27 | import java.util.Hashtable; 28 | 29 | public class QpidSender { public static void main(String args[]) throws Exception{ 30 | 31 | try { 32 | Hashtable properties = new Hashtable<>(); 33 | properties.put("java.naming.factory.initial", "org.apache.qpid.jms.jndi.JmsInitialContextFactory"); 34 | properties.put("connectionFactory.ConnectionFactory", "failover:(amqp://localhost:61616)"); 35 | properties.put("queue.queue/exampleQueue", "exampleQueue"); 36 | InitialContext context = new InitialContext(properties); 37 | 38 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 39 | 40 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 41 | 42 | try ( 43 | Connection connection = cf.createConnection(); 44 | ) { 45 | Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 46 | MessageProducer producer = session.createProducer(queue); 47 | int i = 0; 48 | while (true) { 49 | for (int j = 0 ; j < 10; j++) { 50 | TextMessage textMessage = session.createTextMessage("message " + i++); 51 | producer.send(textMessage); 52 | } 53 | try { 54 | session.commit(); 55 | } catch (TransactionRolledBackException e) { 56 | System.out.println("tx was rolled back after fail over"); 57 | } 58 | Thread.sleep(1000); 59 | } 60 | } 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /demos/broker/high-availability/src/main/java/com/redhat/workshop/amq7/ha/Receiver.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.ha; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.MessageConsumer; 22 | import javax.jms.Queue; 23 | import javax.jms.Session; 24 | import javax.jms.TextMessage; 25 | import javax.naming.InitialContext; 26 | 27 | public class Receiver { 28 | public static void main(String args[]) throws Exception{ 29 | 30 | try { 31 | InitialContext context = new InitialContext(); 32 | 33 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 34 | 35 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 36 | 37 | try ( 38 | Connection connection = cf.createConnection(); 39 | ) { 40 | Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 41 | MessageConsumer consumer = session.createConsumer(queue); 42 | connection.start(); 43 | while (true) { 44 | for (int j = 0 ; j < 10; j++) { 45 | TextMessage receive = (TextMessage) consumer.receive(0); 46 | System.out.println("received message " + receive.getText()); 47 | } 48 | session.commit(); 49 | } 50 | } 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /demos/broker/high-availability/src/main/java/com/redhat/workshop/amq7/ha/Sender.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.ha; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.JMSException; 22 | import javax.jms.MessageProducer; 23 | import javax.jms.Queue; 24 | import javax.jms.Session; 25 | import javax.jms.TextMessage; 26 | import javax.jms.TransactionRolledBackException; 27 | import javax.naming.InitialContext; 28 | 29 | public class Sender { 30 | public static void main(String args[]) throws Exception{ 31 | 32 | try { 33 | InitialContext context = new InitialContext(); 34 | 35 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 36 | 37 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 38 | 39 | try ( 40 | Connection connection = cf.createConnection(); 41 | ) { 42 | Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 43 | MessageProducer producer = session.createProducer(queue); 44 | int i = 0; 45 | while (true) { 46 | for (int j = 0 ; j < 10; j++) { 47 | TextMessage textMessage = session.createTextMessage("message " + i++); 48 | producer.send(textMessage); 49 | System.out.println("sent message " + (i - 1)); 50 | } 51 | try { 52 | session.commit(); 53 | } catch (TransactionRolledBackException e) { 54 | System.out.println("tx was rolled back after fail over"); 55 | } 56 | Thread.sleep(1000); 57 | } 58 | } 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /demos/broker/high-availability/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 2 | connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&retryInterval=1000&retryIntervalMultiplier=1.0&reconnectAttempts=-1 3 | queue.queue/exampleQueue=exampleQueue -------------------------------------------------------------------------------- /demos/broker/large-messages/README.md: -------------------------------------------------------------------------------- 1 | ## Large Messages in AMQ 7 Broker 2 | 3 | This worksheet covers handling large messages in the AMQ7 Broker. By the end of this you should know: 4 | 5 | 1. The large message concepts of AMQ 7 6 | * Memory limits in the broker 7 | * Sending large messages 8 | * Streaming large messages 9 | 10 | 2. How to configure Large Messages 11 | * Configuring a broker to handle large messages 12 | * Configuring a client to use large messages 13 | * Configuring a client to stream messages 14 | 15 | 16 | ### Large Message Concepts 17 | 18 | There are 2 main issues that can happen when you send or receive messages to an AMQ 7 Broker. 19 | 20 | 1. Memory limits are exceeded in the broker 21 | 2. Memory limits are exceeded within the client 22 | 23 | #### Memory Limits Within the Broker 24 | 25 | Any message that is sent or consumed from a Broker has to exist in memory at some point before 26 | it can either be persisted to disk after receipt, or delivered to a consumer. This can be problematic 27 | when running in an environment with limited memory. The AMQ 7 broker handles large messages by never 28 | fully reading them into memory, instead the broker writes the large message directly to its large message store 29 | located on disk. The location of this is configured in the broker.xml file like so: 30 | 31 | ```xml 32 | largemessagesdir 33 | ``` 34 | This is always configured by default. 35 | 36 | #### Large Messages and Clients 37 | 38 | Currently only the Core JMS client can handle large messages 39 | 40 | ##### Sending a Large Message 41 | 42 | To configure the core JMS client to send a message you need to configure `min-large-message-size` on 43 | the connection factory. The `min-large-message-size` parameter is used in the client to determine when to mark a message 44 | as *large*. There are a handful of ways to configure the `min-large-message-size` parameter on the connection factory. 45 | 46 | 1. Using JNDI 47 | 48 | If JNDI is used to instantiate and look up the connection factory, the minimum large message size is configured in the 49 | JNDI context environment, e.g. `jndi.properties`. Here's a simple example using the "ConnectionFactory" connection factory 50 | which is available in the context by default: 51 | 52 | ```properties 53 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 54 | connectionFactory.myConnectionFactory=tcp://localhost:61616?minLargeMessageSize=10240 55 | ``` 56 | 57 | 2. In Java code 58 | 59 | If the connection factory is being instantiated directly in Java, the minimum 60 | large message size can be specified like so: 61 | 62 | ```java 63 | ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(); 64 | cf.setMinLargeMessageSize(10240); 65 | ``` 66 | 67 | or using the URL: 68 | 69 | ```java 70 | new ActiveMQConnectionFactory("tcp://localhost:61616?minLargeMessageSize=10240"); 71 | ``` 72 | 73 | To see this in action start a broker in the usual fashion. 74 | 75 | Use the `com.redhat.workshop.amq7.largemessage.Sender` to send a large message: 76 | 77 | ```sh 78 | $ mvn verify -PLargeMessageSender 79 | ``` 80 | 81 | Since the `minLargeMessageSize` size in the example is set to `10240` bytes and the `Sender` client is sending 82 | a bytes message of size `20480` bytes, the client will treat this as a large message and send it in chunks. 83 | 84 | The broker will then write these chunks to its large message store without having to keep them in memory. 85 | Obviously, in reality the large message can be as large as the client can fit into memory. 86 | 87 | Take a look in the `large-messages-directory`. You will notice a new file that contains the content of the message 88 | Note: The content is encoded so it's not human readable. 89 | 90 | You can consume the message using the `com.redhat.workshop.amq7.largemessage.Receiver` client by running: 91 | 92 | ```sh 93 | $ mvn verify -PLargeMessageReceiver 94 | ``` 95 | 96 | Note that the large message file has now disappeared. 97 | 98 | #### Memory Limits within the Broker 99 | 100 | In the previous example, we created a single byte array that contained the whole large message. If client 101 | memory is also constrained this may not be possible. 102 | 103 | ##### Streaming a Large Message 104 | 105 | However, it is possible to stream a message straight from disk or another type of Input Stream. This can only be done via the JMS API by sending a JMS BytesMessage and setting an input stream as an Object property, like so 106 | 107 | ```java 108 | BytesMessage bytesMessage = session.createBytesMessage(); 109 | FileInputStream fileInputStream = new FileInputStream(inputFile); 110 | BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream); 111 | bytesMessage.setObjectProperty("JMS_AMQ_InputStream", bufferedInput); 112 | ``` 113 | 114 | The client will stream the contents of the file direct to the TCP stream in chunks. 115 | This is then handled by the Broker as a large message. To see this in action use the 116 | `com.redhat.workshop.amq7.streammessage.Sender`. 117 | 118 | ```sh 119 | $ mvn verify -PStreamMessageSender 120 | ``` 121 | 122 | Inspect the large message store and you will again see the large message file. 123 | 124 | To consume a stream message you simple consume a JMS BytesMessage with an OutputStream using the JMS API like so: 125 | 126 | 127 | ```java 128 | BytesMessage messageReceived = (BytesMessage) messageConsumer.receive(120000); 129 | File outputFile = new File("huge_message_received.dat"); 130 | FileOutputStream fileOutputStream = new FileOutputStream(outputFile) 131 | BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream); 132 | 133 | //This will save the stream and wait until the entire message is written before continuing. 134 | messageReceived.setObjectProperty("JMS_AMQ_SaveStream", bufferedOutput); 135 | ``` 136 | 137 | To see this in action use the 138 | `com.redhat.workshop.amq7.streammessage.Receiver` to receive a stream message like so: 139 | 140 | ```sh 141 | $ mvn verify -PStreamMessageReceiver 142 | ``` 143 | 144 | > ##### Note 145 | > 146 | > Stream messages and large messages are interchangeable so you can send a large 147 | > message and consume a stream message and vice versa. 148 | -------------------------------------------------------------------------------- /demos/broker/large-messages/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | 25 | com.redhat.workshop.amq 26 | broker-demos 27 | 1.0.0 28 | 29 | 30 | largeMessage 31 | 1.0.0 32 | jar 33 | AMQ 7 JMS Large Message Example 34 | 35 | 36 | 37 | org.apache.geronimo.specs 38 | geronimo-jms_2.0_spec 39 | 40 | 41 | org.apache.activemq 42 | artemis-commons 43 | 44 | 45 | org.apache.activemq 46 | artemis-jms-client 47 | 48 | 49 | 50 | 51 | 52 | LargeMessageSender 53 | 54 | 55 | 56 | org.codehaus.mojo 57 | exec-maven-plugin 58 | 1.1 59 | 60 | 61 | verify 62 | 63 | java 64 | 65 | 66 | 67 | 68 | com.redhat.workshop.amq7.largemessage.Sender 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | LargeMessageReceiver 77 | 78 | 79 | 80 | org.codehaus.mojo 81 | exec-maven-plugin 82 | 1.1 83 | 84 | 85 | verify 86 | 87 | java 88 | 89 | 90 | 91 | 92 | com.redhat.workshop.amq7.largemessage.Receiver 93 | 94 | 95 | 96 | 97 | 98 | 99 | StreamMessageSender 100 | 101 | 102 | 103 | org.codehaus.mojo 104 | exec-maven-plugin 105 | 1.1 106 | 107 | 108 | verify 109 | 110 | java 111 | 112 | 113 | 114 | 115 | com.redhat.workshop.amq7.streammessage.Sender 116 | 117 | 118 | 119 | 120 | 121 | 122 | StreamMessageReceiver 123 | 124 | 125 | 126 | org.codehaus.mojo 127 | exec-maven-plugin 128 | 1.1 129 | 130 | 131 | verify 132 | 133 | java 134 | 135 | 136 | 137 | 138 | com.redhat.workshop.amq7.streammessage.Receiver 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /demos/broker/large-messages/src/main/java/com/redhat/workshop/amq7/largemessage/Receiver.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.largemessage; 18 | 19 | import javax.jms.Connection; 20 | import javax.jms.ConnectionFactory; 21 | import javax.jms.Message; 22 | import javax.jms.MessageConsumer; 23 | import javax.jms.Queue; 24 | import javax.jms.Session; 25 | import javax.naming.InitialContext; 26 | 27 | public class Receiver { 28 | public static void main(String args[]) throws Exception{ 29 | 30 | try { 31 | InitialContext context = new InitialContext(); 32 | 33 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 34 | 35 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 36 | 37 | try ( 38 | Connection connection = cf.createConnection(); 39 | ) { 40 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 41 | MessageConsumer consumer = session.createConsumer(queue); 42 | connection.start(); 43 | Message message = consumer.receiveNoWait(); 44 | System.out.println("received message from broker " + message); 45 | } 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /demos/broker/large-messages/src/main/java/com/redhat/workshop/amq7/largemessage/Sender.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.largemessage; 18 | 19 | 20 | import javax.jms.BytesMessage; 21 | import javax.jms.Connection; 22 | import javax.jms.MessageProducer; 23 | import javax.jms.Queue; 24 | import javax.jms.Session; 25 | import javax.naming.InitialContext; 26 | import javax.jms.ConnectionFactory; 27 | 28 | public class Sender { 29 | public static void main(String args[]) throws Exception{ 30 | 31 | try { 32 | InitialContext context = new InitialContext(); 33 | 34 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 35 | 36 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 37 | 38 | try ( 39 | Connection connection = cf.createConnection(); 40 | ) { 41 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 42 | MessageProducer producer = session.createProducer(queue); 43 | BytesMessage bytesMessage = session.createBytesMessage(); 44 | 45 | // Send a 100MB message 46 | byte[] bytes = new byte[100 * 1024 * 1024]; 47 | bytesMessage.writeBytes(bytes); 48 | producer.send(bytesMessage); 49 | } 50 | } catch (Exception e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /demos/broker/large-messages/src/main/java/com/redhat/workshop/amq7/streammessage/Receiver.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.streammessage; 18 | 19 | 20 | import javax.jms.BytesMessage; 21 | import javax.jms.Connection; 22 | import javax.jms.ConnectionFactory; 23 | import javax.jms.MessageConsumer; 24 | import javax.jms.Queue; 25 | import javax.jms.Session; 26 | import javax.naming.InitialContext; 27 | import java.io.BufferedOutputStream; 28 | import java.io.File; 29 | import java.io.FileOutputStream; 30 | 31 | public class Receiver { 32 | public static void main(String args[]) throws Exception{ 33 | 34 | try { 35 | InitialContext context = new InitialContext(); 36 | 37 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 38 | 39 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 40 | 41 | try ( 42 | Connection connection = cf.createConnection(); 43 | ) { 44 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 45 | 46 | connection.start(); 47 | 48 | MessageConsumer messageConsumer = session.createConsumer(queue); 49 | 50 | connection.start(); 51 | 52 | BytesMessage messageReceived = (BytesMessage) messageConsumer.receive(120000); 53 | 54 | File outputFile = new File("huge_message_received.dat"); 55 | 56 | try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) { 57 | BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutputStream); 58 | 59 | //This will save the stream and wait until the entire message is written before continuing. 60 | messageReceived.setObjectProperty("JMS_AMQ_SaveStream", bufferedOutput); 61 | } 62 | } 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /demos/broker/large-messages/src/main/java/com/redhat/workshop/amq7/streammessage/Sender.java: -------------------------------------------------------------------------------- 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 | package com.redhat.workshop.amq7.streammessage; 18 | 19 | 20 | import javax.jms.BytesMessage; 21 | import javax.jms.Connection; 22 | import javax.jms.ConnectionFactory; 23 | import javax.jms.MessageProducer; 24 | import javax.jms.Queue; 25 | import javax.jms.Session; 26 | import javax.naming.InitialContext; 27 | import java.io.BufferedInputStream; 28 | import java.io.BufferedOutputStream; 29 | import java.io.File; 30 | import java.io.FileInputStream; 31 | import java.io.FileOutputStream; 32 | import java.io.IOException; 33 | import java.util.Random; 34 | 35 | import org.apache.activemq.artemis.utils.RandomUtil; 36 | 37 | public class Sender { 38 | 39 | private static final long FILE_SIZE = 1L;//1 GiB message 40 | 41 | public static void main(String args[]) { 42 | try { 43 | File inputFile = new File("huge_message_to_send.dat"); 44 | 45 | createFile(inputFile, FILE_SIZE); 46 | 47 | InitialContext context = new InitialContext(); 48 | 49 | Queue queue = (Queue) context.lookup("queue/exampleQueue"); 50 | 51 | ConnectionFactory cf = (ConnectionFactory) context.lookup("ConnectionFactory"); 52 | 53 | try ( 54 | Connection connection = cf.createConnection(); 55 | ) { 56 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 57 | MessageProducer producer = session.createProducer(queue); 58 | BytesMessage bytesMessage = session.createBytesMessage(); 59 | FileInputStream fileInputStream = new FileInputStream(inputFile); 60 | BufferedInputStream bufferedInput = new BufferedInputStream(fileInputStream); 61 | bytesMessage.setObjectProperty("JMS_AMQ_InputStream", bufferedInput); 62 | producer.send(bytesMessage); 63 | } 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | private static void createFile(final File file, final long fileSize) throws IOException { 69 | FileOutputStream fileOut = new FileOutputStream(file); 70 | try (BufferedOutputStream buffOut = new BufferedOutputStream(fileOut)) { 71 | 72 | // Sends a 10MB file 73 | for (int r = 0; r < 10 * 1024; r++) { 74 | for (long c = 0; c < 1023; c ++) { 75 | buffOut.write(RandomUtil.randomChar()); 76 | } 77 | buffOut.write('\n'); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /demos/broker/large-messages/src/main/resources/jndi.properties: -------------------------------------------------------------------------------- 1 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 2 | connectionFactory.ConnectionFactory=tcp://localhost:61616?minLargeMessageSize=10240 3 | queue.queue/exampleQueue=exampleQueue -------------------------------------------------------------------------------- /demos/broker/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 4.0.0 23 | 24 | com.redhat.workshop.amq 25 | broker-demos 26 | 1.0.0 27 | pom 28 | AMQ 7 Broker Demos 29 | 30 | 31 | 1.8 32 | 1.8 33 | 2.0.0.amq-700005-redhat-1 34 | 1.0.0.alpha-2-redhat-2 35 | 0.23.0 36 | 37 | 38 | 39 | 40 | Red Hat Maven 41 | redhat 42 | https://maven.repository.redhat.com/ga/ 43 | 44 | 45 | 46 | 47 | addressing 48 | large-messages 49 | high-availability 50 | 51 | 52 | 53 | 54 | 55 | org.apache.qpid 56 | qpid-jms-client 57 | ${qpid.jms.version} 58 | 59 | 60 | org.apache.activemq 61 | artemis-commons 62 | ${amq7.version} 63 | 64 | 69 | 70 | org.apache.activemq 71 | artemis-jms-client 72 | ${amq7.version} 73 | 74 | 75 | org.apache.geronimo.specs 76 | geronimo-jms_2.0_spec 77 | ${geronimo.spec.version} 78 | 79 | 80 | org.apache.qpid 81 | qpid-jms-client 82 | 0.21.0.redhat-1 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /demos/broker/security/README.md: -------------------------------------------------------------------------------- 1 | # Security in AMQ 7 broker 2 | 3 | This worksheet covers security in the AMQ 7 broker. By the end of this you should know: 4 | 5 | 1. How the AMQ 7 security architecture compares to AMQ 6 6 | 2. How to require authentication and manipulate user data using the default JAAS properties login module 7 | 3. How to grant a user access to certain permissions via role-based authorization 8 | 4. How to configure SSL 9 | 10 | ## AMQ 7 vs. AMQ 6 11 | 12 | Those familiar with AMQ 6 security will find lots of similarities in AMQ 7. Both brokers leverage JAAS. If you're unfamiliar with JAAS you can get a quick overview [here](https://en.wikipedia.org/wiki/Java_Authentication_and_Authorization_Service). These JAAS login modules have ported over from AMQ 6 to AMQ 7 with minimal changes: 13 | * Properties files 14 | * LDAP 15 | * SSL certificate 16 | * Guest 17 | 18 | The "dual" authentication feature is also present in AMQ 7. This feature allows independent JAAS domains for SSL and non-SSL connections. 19 | 20 | AMQ 6 has these permission types: 21 | 22 | * **read** 23 | * **write** 24 | * **admin** 25 | 26 | Whereas AMQ 7 has these permission types: 27 | 28 | * **createDurableQueue** allows the user to create a durable queue 29 | * **deleteDurableQueue** allows the user to delete a durable queue 30 | * **createNonDurableQueue** allows the user to create a non-durable queue 31 | * **deleteNonDurableQueue** allows the user to delete a non-durable queue 32 | * **send** allows the user to send a message 33 | * **consume** allows the user to consume a message from a queue bound to matching addresses 34 | * **browse** allows the user to browse a queue bound to the matching address 35 | * **manage** allows the user to invoke management operations by sending management messages to the management address 36 | 37 | Creating and deleting queues is particularly important in AMQ 7 as that is how subscriptions are implemented. For example, a JMS client wanting to create a durable subscription would need the `createDurableQueue` permission. 38 | 39 | ## Authentication 40 | 41 | Configuration starts in `AMQ_INSTANCE/etc/bootstrap.xml`. This is the default configuration: 42 | 43 | 44 | 45 | The `domain` attribute refers to the relevant login module entry in `AMQ_INSTANCE/etc/login.config`. For example, if an instance were created with the following command: 46 | 47 | ``` 48 | $ /bin/artemis create --user admin --password password --role admin --allow-anonymous /instances/mybroker 49 | ``` 50 | 51 | Then this would appear in `login.config`: 52 | 53 | activemq { 54 | org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient 55 | debug=false 56 | reload=true 57 | org.apache.activemq.jaas.properties.user="artemis-users.properties" 58 | org.apache.activemq.jaas.properties.role="artemis-roles.properties"; 59 | 60 | org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient 61 | debug=false 62 | org.apache.activemq.jaas.guest.user="admin" 63 | org.apache.activemq.jaas.guest.role="admin"; 64 | }; 65 | 66 | The `--allow-anonymous` switch in the `artemis create` command ensures the "guest" login module is added to `login.config` so that anonymous users can access the broker. By default, anonymous are assigned the user and role also specified in the `artemis create` command via the `user` and `role` switches. Alternatively one can omit `--allow-anonymous` and specify `--require-login` instead and the "guest" login module will be omitted from `login.config`. 67 | 68 | By default user credentials and role information are stored in the properties files `artemis-users.properties` and `artemis-roles.properties` respectively. 69 | 70 | The `artemis-users.properties` file consists of a list of properties of the form, `UserName=Password`. For example, to define the users `system`, `user`, and `guest`, you could create a file like the following: 71 | 72 | ```properties 73 | system=systemPassword 74 | user=userPassword 75 | guest=guestPassword 76 | ``` 77 | 78 | The `artemis-roles.properties` file consists of a list of properties of the form, `Role=UserList`, where UserList is a comma-separated list of users. For example, to define the roles `admins`, `users`, and `guests`, you could create a file like the following: 79 | 80 | ```properties 81 | admins=system 82 | users=system,user 83 | guests=guest 84 | ``` 85 | 86 | 87 | By default passwords are hashed using `PBKDF2WithHmacSHA1`. However, un-hashed passwords can be manually added if desired by creating an entry without the ENC() syntax. 88 | 89 | The CLI support commands to manipulate these files, e.g.: 90 | 91 | ``` 92 | $ /bin/artemis user add|rm|list|reset 93 | ``` 94 | 95 | ### Hands on 96 | 97 | Create a new broker instance using this command where `` and `` are whatever you choose: 98 | 99 | ``` 100 | $ /bin/artemis create --user --password --role admin --require-login /instances/mysecurebroker 101 | ``` 102 | 103 | Start that instance using this command: 104 | 105 | ``` 106 | $ /bin/artemis run 107 | ``` 108 | 109 | Run this command, passing in the user and password specified when the instance was created. 110 | 111 | ``` 112 | $ /bin/artemis producer --message-count 1 --user --password 113 | ``` 114 | 115 | Now run it again with a new user and password. 116 | 117 | ``` 118 | $ /bin/artemis producer --message-count 1 --user --password 119 | ``` 120 | 121 | This will fail because the broker doesn't recognize the user. 122 | 123 | Add this new user to the broker (make sure the `role` is the same as when the instance was created): 124 | 125 | ``` 126 | $ /bin/artemis user add --user --password --role admin 127 | ``` 128 | 129 | The broker will automatically reload the properties files so that the new user is now valid. Run this command, passing in the *new* user and *new* password which were just added. 130 | 131 | ``` 132 | $ /bin/artemis producer --message-count 1 --user --password 133 | ``` 134 | 135 | Open `AMQ_INSTANCE/etc/artemis-users.properties` and see the new user and its hashed password. 136 | 137 | ## Authorization 138 | 139 | Authorization is configured in `AMQ_INSTANCE/etc/broker.xml` in the `` element. Here is the default configuration from an instance created via this command: 140 | 141 | ``` 142 | $ /bin/artemis create --user admin --password password --role admin --allow-anonymous /instances/mybroker 143 | ``` 144 | 145 | The role specified in the command via the `role` switch is inserted into the `roles` attribute. 146 | 147 | ```xml 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | ``` 164 | 165 | A `security-setting` matches one or more addresses via the `match` attribute. The matching functionality supports wildcards like `#` which signifies "any sequence of words." See [the documentation](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/addresses#wildcard_syntax) for more details about the wildcard syntax. 166 | 167 | Since the default `security-setting` matches `#` and refers only to the `admin` role that means only users in the `admin` role can perform any real work. 168 | 169 | ### Hands on 170 | 171 | Remove the user you created previously (which was in the `admin` role): 172 | 173 | ``` 174 | $ /bin/artemis user rm --user 175 | ``` 176 | 177 | Recreate that user in a different role: 178 | 179 | ``` 180 | $ /bin/artemis user add --user --password --role 181 | ``` 182 | 183 | Attempt to send a message with this user: 184 | 185 | ``` 186 | $ /bin/artemis producer --message-count 1 --user --password 187 | ``` 188 | 189 | You should see an error with something like this: 190 | 191 | ``` 192 | User: does not have permission='SEND' on address TEST 193 | ``` 194 | 195 | Modify the `security-setting` to allow your new user to send: 196 | 197 | ```xml 198 | 199 | ``` 200 | 201 | The running broker will automatically reload the modified `security-settings`. Now attempt to send again: 202 | 203 | ``` 204 | $ /bin/artemis producer --message-count 1 --user --password 205 | ``` 206 | 207 | The send will now succeed. 208 | 209 | ## SSL 210 | 211 | Both one-way and two-way SSL are supported. 212 | 213 | SSL artifact configuration can be done a few different ways: 214 | 215 | * Standard system properties: 216 | 217 | ```text 218 | javax.net.ssl.keyStore 219 | javax.net.ssl.keyStorePassword 220 | javax.net.ssl.trustStore 221 | javax.net.ssl.trustStorePassword 222 | ``` 223 | 224 | * Broker-specific system properties (will override standard system properties): 225 | 226 | ```text 227 | org.apache.activemq.ssl.keyStore 228 | org.apache.activemq.ssl.keyStorePassword 229 | org.apache.activemq.ssl.trurestStore 230 | org.apache.activemq.ssl.trustStorePassword 231 | ``` 232 | 233 | * URL (either on a connector or acceptor): 234 | 235 | tcp://localhost:5500?sslEnabled=true;__keyStorePath__=../etc/activemq.example.keystore;__keyStorePassword__=activemqexample;__trustStorePath__=../etc/activemq.example.truststore;__trustStorePassword__=activemqexample 236 | 237 | Regardless of how the SSL artifacts are configured the `sslEnabled` URL property must always be `true`. 238 | 239 | An acceptor can require a client-side certificate by setting the `needClientAuth` URL property to `true`. 240 | 241 | ## Misc 242 | 243 | To disable security completely simply set the `security-enabled` property to false in the `broker.xml` file. 244 | 245 | For performance reasons security is cached and invalidated every so long. To change this period set the property `security-invalidation-interval`, which is in milliseconds. The default is `10000` ms. 246 | 247 | Password masking is supported. 248 | -------------------------------------------------------------------------------- /dockerfiles/interconnnect/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/rhel7/rhel 2 | 3 | MAINTAINER Andrew Block 4 | 5 | LABEL io.k8s.description="Lightweight AMQP message router for building scalable, available, and performant messaging networks." \ 6 | io.k8s.display-name="AMQ Interconnect Dispatch Router" \ 7 | io.openshift.tags="amq,java,interconnect,router" \ 8 | io.openshift.expose-services="5671,5001,5672,55672,10002,10003" 9 | 10 | 11 | RUN yum repolist > /dev/null && \ 12 | yum-config-manager --enable amq-interconnect-1-for-rhel-7-server-rpms --enable a-mq-clients-1-for-rhel-7-server-rpms && \ 13 | yum clean all && \ 14 | INSTALL_PKGS="qpid-proton-c \ 15 | python-qpid-proton \ 16 | qpid-dispatch-router \ 17 | qpid-dispatch-tools" && \ 18 | yum install -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ 19 | rpm -V $INSTALL_PKGS && \ 20 | yum clean all 21 | 22 | EXPOSE 5001 5672 55672 10002 10003 23 | 24 | CMD ["/usr/sbin/qdrouterd", "-c", "/etc/qpid-dispatch/qdrouterd.conf"] -------------------------------------------------------------------------------- /dockerfiles/qdr/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:centos7.3.1611 2 | 3 | RUN rpm -i https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 4 | RUN yum -y update 5 | RUN yum -y install qpid-proton-c-devel python-qpid-proton man 6 | 7 | WORKDIR /opt/amq7 8 | 9 | RUN mkdir -p /opt/amq7/router 10 | 11 | COPY ./rpms ./router 12 | 13 | RUN rpm -Uvh ./router/*.rpm 14 | 15 | VOLUME /etc/qpid-dispatch/ 16 | 17 | EXPOSE 5672 55672 5671 18 | CMD ["/usr/sbin/qdrouterd", "--conf", "/etc/qpid-dispatch/qdrouterd.conf"] -------------------------------------------------------------------------------- /labs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/.gitkeep -------------------------------------------------------------------------------- /labs/00-install-broker.md: -------------------------------------------------------------------------------- 1 | # Installing the AMQ7 Broker 2 | 3 | To begin, verify you have [all of the prerequisites](README.md) for these labs. 4 | 5 | As a reminder, JBoss AMQ7 comes with four main components: 6 | 7 | * AMQ7 Broker 8 | * AMQ7 Interconnect Router 9 | * AMQ7 Clients 10 | * Management Console 11 | 12 | The Broker comes with the management console, but the Interconnect Router and each individual client comes as a separate binary/download/installation. 13 | 14 | We'll start by downloading the binaries for JBoss AMQ 7 Broker. In later labs, we'll get to the [clients](20-clients.md) as well as the [interconnect router](80-install-qdr.md) 15 | 16 | All of the components are available at the [Downloads page](https://developers.redhat.com/products/amq/download/) of [https://developers.redhat.com/products/amq/overview/](https://developers.redhat.com/products/amq/overview/). Navigate to that page and download the AMQ7 Broker: 17 | 18 | ![Download AMQ7 Broker](images/install/downloadbroker.png) 19 | 20 | Alternatively, if you are a current Red Hat customer, you can download the latest AMQ7 (and any associated patches) from the [Red Hat Customer Portal](https://access.redhat.com/products/red-hat-jboss-amq/). Even if you don't currently have JBoss AMQ subscriptions, you still have access to all of the Red Hat products and documentation for development/evaluation purposes. 21 | 22 | Once you click one of the download links and you have the broker downloaded, navigate to your command line (Powershell, Bash, Cygwin, etc) and locate the newly downloaded file (e.g. `jboss-amq-7.0.0.redhat-1-bin.zip`). You can move this .zip file to a location of your choosing (e.g. ~/dev/labs or similar). 23 | 24 | Using your favorite `unzip` utility, unzip the `jboss-amq-7.0.0.redhat-1-bin.zip` binary file and navigate into the newly created directory: 25 | 26 | $ unzip jboss-amq-7.0.0.redhat-1-bin.zip 27 | $ cd jboss-amq-7.0.0.redhat-1 28 | 29 | If you do a listing of the directory, you should see something similar to this: 30 | 31 | $ ls -l 32 | 33 | ``` 34 | total 56 35 | -rw-r--r--@ 1 ceposta staff 15K Apr 21 11:25 LICENSE 36 | -rw-r--r--@ 1 ceposta staff 179B Apr 21 11:25 NOTICE 37 | -rw-r--r--@ 1 ceposta staff 4.7K Apr 21 11:25 README.html 38 | drwxrwxr-x@ 5 ceposta staff 170B May 3 06:55 bin 39 | drwxrwxr-x@ 3 ceposta staff 102B May 3 06:55 etc 40 | drwxrwxr-x@ 7 ceposta staff 238B May 3 06:55 examples 41 | drwxrwxr-x@ 49 ceposta staff 1.6K Apr 21 11:48 lib 42 | drwxrwxr-x@ 5 ceposta staff 170B May 3 06:55 schema 43 | drwxrwxr-x@ 16 ceposta staff 544B May 3 06:55 web 44 | 45 | ``` 46 | 47 | Let's have a look at each folder: 48 | 49 | * `bin` -- Set up scripts for creating and managing brokers 50 | * `etc` -- Bootstrap settings for running `artemis` commands 51 | * `examples` -- handful of useful examples for getting started with AMQ7 52 | * `lib` -- where the AMQ7 libs and dependencies are packaged 53 | * `schema` -- config files schemas 54 | * `web` -- where the main web console configuration and libraries are stored 55 | 56 | ## Creating a Broker 57 | 58 | Up until this point, we've just download the main binaries and bootstrap configuration, but we still don't have a broker. 59 | 60 | > Note this is a bit different from AMQ6 if you've used that in the past. In AMQ6, the initial binary download was the broker itself. With AMQ7, we need to explicitly create a broker with the settings that we prefer. 61 | 62 | Let's create a new folder in a location we choose (could be inside the installation folder if we'd like) called `brokers` and let's create a new broker inside of it: 63 | 64 | $ mkdir brokers 65 | $ ./bin/artemis create brokers/myfirstbroker 66 | 67 | You'll be prompted to enter information that we've left off the command line. Fill in the user, password, and other information similar to this: 68 | 69 | ``` 70 | Creating ActiveMQ Artemis instance at: /Users/ceposta/dev/activemq/jboss-amq-7.0.0.redhat-1/brokers/myfirstbroker 71 | 72 | --user: is a mandatory property! 73 | Please provide the default username: 74 | admin 75 | 76 | --password: is mandatory with this configuration: 77 | Please provide the default password: 78 | 79 | 80 | --allow-anonymous | --require-login: is a mandatory property! 81 | Allow anonymous access?, valid values are Y,N,True,False 82 | Y 83 | 84 | Auto tuning journal ... 85 | done! Your system can make 14.71 writes per millisecond, your journal-buffer-timeout will be 68000 86 | 87 | You can now start the broker by executing: 88 | 89 | "/Users/ceposta/dev/activemq/jboss-amq-7.0.0.redhat-1/brokers/myfirstbroker/bin/artemis" run 90 | 91 | Or you can run the broker in the background using: 92 | 93 | "/Users/ceposta/dev/activemq/jboss-amq-7.0.0.redhat-1/brokers/myfirstbroker/bin/artemis-service" start 94 | ``` 95 | 96 | Congrats! You've just created your *first* AMQ7 broker :) 97 | 98 | Note that some auto-tuning was done based on your environment. This is pretty handy when it comes to selecting the appropriate configuration for your persistent messaging use cases, but we'll come back to that in a subsequent lab. 99 | 100 | If you're curious what command-line arguments you *can* pass to the `create` command, use the `help` command like this: 101 | 102 | $ ./bin/artemis help 103 | 104 | So in this case, we'd list the help documentation for the `create` command like this: 105 | 106 | $ ./bin/artemis help create 107 | 108 | ## Starting our new broker 109 | 110 | In the previous section, we created a new broker and in the output of the command we saw instructions for how to start the broker. 111 | Before we do that, let's navigate to our new `brokers/myfirstbroker` folder and check out the directory structure and see what was created. 112 | 113 | $ cd brokers/myfirstbroker 114 | $ ls -l 115 | 116 | ``` 117 | drwxr-xr-x 4 ceposta staff 136B May 10 13:58 bin 118 | drwxr-xr-x 2 ceposta staff 68B May 10 13:58 data 119 | drwxr-xr-x 9 ceposta staff 306B May 10 13:58 etc 120 | drwxr-xr-x 2 ceposta staff 68B May 10 13:58 log 121 | drwxr-xr-x 2 ceposta staff 68B May 10 13:58 tmp 122 | ``` 123 | 124 | These are the folders in the newly created broker `myfirstbroker`. Let's see what they have in them: 125 | 126 | * `bin` -- scripts to control the lifecycle of our new broker 127 | * `data` -- where all of the transaction/journal logs are stored for our messages 128 | * `etc` -- the configuration for our broker 129 | * `log` -- the log output from running our broker 130 | * `tmp` -- temporary disk usage 131 | 132 | We'll start the new broker in the foreground with the following: 133 | 134 | $ ./bin/artemis run 135 | 136 | ``` 137 | __ __ ____ ____ _ 138 | /\ | \/ |/ __ \ | _ \ | | 139 | / \ | \ / | | | | | |_) |_ __ ___ | | _____ _ __ 140 | / /\ \ | |\/| | | | | | _ <| '__/ _ \| |/ / _ \ '__| 141 | / ____ \| | | | |__| | | |_) | | | (_) | < __/ | 142 | /_/ \_\_| |_|\___\_\ |____/|_| \___/|_|\_\___|_| 143 | 144 | Red Hat JBoss AMQ 7.0.0.redhat-1 145 | 146 | 147 | 14:07:31,490 INFO [org.apache.activemq.artemis.integration.bootstrap] AMQ101000: Starting ActiveMQ Artemis Server 148 | 14:07:31,540 INFO [org.apache.activemq.artemis.core.server] AMQ221000: live Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=./data/journal,bindingsDirectory=./data/bindings,largeMessagesDirectory=./data/large-messages,pagingDirectory=./data/paging) 149 | 14:07:31,578 INFO [org.apache.activemq.artemis.core.server] AMQ221013: Using NIO Journal 150 | 14:07:31,671 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE 151 | 14:07:31,671 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-amqp-protocol]. Adding protocol support for: AMQP 152 | 14:07:31,671 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-hornetq-protocol]. Adding protocol support for: HORNETQ 153 | 14:07:31,672 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-mqtt-protocol]. Adding protocol support for: MQTT 154 | 14:07:31,672 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-openwire-protocol]. Adding protocol support for: OPENWIRE 155 | 14:07:31,672 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-stomp-protocol]. Adding protocol support for: STOMP 156 | 14:07:31,716 INFO [org.apache.activemq.artemis.core.server] AMQ221034: Waiting indefinitely to obtain live lock 157 | 14:07:31,717 INFO [org.apache.activemq.artemis.core.server] AMQ221035: Live Server Obtained live lock 158 | 14:07:31,865 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue DLQ 159 | 14:07:31,931 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue ExpiryQueue 160 | 14:07:32,733 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:61616 for protocols [CORE,MQTT,AMQP,STOMP,HORNETQ,OPENWIRE] 161 | 14:07:32,735 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:5445 for protocols [HORNETQ,STOMP] 162 | 14:07:32,737 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:5672 for protocols [AMQP] 163 | 14:07:32,739 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:1883 for protocols [MQTT] 164 | 14:07:32,741 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:61613 for protocols [STOMP] 165 | 14:07:32,741 INFO [org.apache.activemq.artemis.core.server] AMQ221007: Server is now live 166 | 14:07:32,742 INFO [org.apache.activemq.artemis.core.server] AMQ221001: Apache ActiveMQ Artemis Message Broker version 2.0.0.amq-700005-redhat-1 [0.0.0.0, nodeID=ae7bf278-35c4-11e7-97d9-0a0027000001] 167 | INFO | main | Initialized artemis-plugin plugin 168 | INFO | main | Initialized dispatch-hawtio-console plugin 169 | 14:07:35,393 INFO [org.apache.activemq.artemis] AMQ241001: HTTP Server started at http://localhost:8161 170 | 14:07:35,394 INFO [org.apache.activemq.artemis] AMQ241002: Artemis Jolokia REST API available at http://localhost:8161/jolokia 171 | ``` 172 | 173 | Yay! We've got our broker installed and running! 174 | 175 | Take a quick glance at the log output and note a few things: 176 | 177 | * The location of our transaction logs and cluster configuration 178 | * We're using the NIO Journal for persistence 179 | * We have a single port, `61616` that can accept connections for multiple protocols (i.e. `CORE`, `MQTT`, `AMQP`, `STOMP`, `HORNETQ`, `OPENWIRE`) 180 | * We have individual ports for each protocol as well 181 | * We see that the web console has been started at `http://localhost:8161` 182 | * We see that the Jolokia (a JMX over REST) service has been started at `http://localhost:8161/jolokia` 183 | 184 | That's it for this lab! 185 | 186 | To learn more about getting started, see the [product documentation at the Red Hat support portal!](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/getting_started) 187 | -------------------------------------------------------------------------------- /labs/10-configure-broker.md: -------------------------------------------------------------------------------- 1 | # Configuring AMQ 7 2 | 3 | In this lab, we'll take a look at the AMQ7 configuration files and some basic configuration options and things to be aware of. We'll dig into more specific configurations (like persistence, clustering, etc) in later labs. 4 | 5 | If we navigate back to our `brokers/myfirstbroker` installation that we created in the previous lab we can examine our configuration. AMQ7 configuration is stored in `etc/` folder. If we do a listing of the `etc/` folder we should see something similar to the following: 6 | 7 | $ cd brokers/myfirstbroker 8 | $ ls -l ./etc/ 9 | 10 | ``` 11 | total 64 12 | -rw-r--r-- 1 ceposta staff 961B May 10 13:58 artemis-roles.properties 13 | -rw-r--r-- 1 ceposta staff 1.1K May 10 13:58 artemis-users.properties 14 | -rw-r--r-- 1 ceposta staff 2.0K May 10 13:58 artemis.profile 15 | -rw-r--r-- 1 ceposta staff 1.6K May 10 13:58 bootstrap.xml 16 | -rw-r--r-- 1 ceposta staff 8.0K May 10 13:58 broker.xml 17 | -rw-r--r-- 1 ceposta staff 2.2K May 10 13:58 logging.properties 18 | -rw-r--r-- 1 ceposta staff 1.3K May 10 13:58 login.config 19 | ``` 20 | 21 | 22 | For the sake of this lab, we're going to look closer at the following files 23 | 24 | * `bootstrap.xml` -- the entry point to starting a broker 25 | * `broker.xml` -- the main broker configuration file; configures network connections, security, message addresses, etc. 26 | 27 | If you'd like more information on the rest of the files, [see the product documentation on the Red Hat Customer Support portal](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/basic_configuration#configuration_files_and_locations). 28 | 29 | ### bootstrap.xml 30 | 31 | The `bootstrap.xml` file is fairly straight forward and contains a small set of configurations for starting a broker. The most important configuration here is the `` element. This configuration setting allows us to instruct the bootstrap runtime where the main configuration file is. We may opt to keep these configuration settings in a version controlled repository that gets installed into the server where the AMQ7 broker runs independently of how/when the broker gets created. Alternatively, if we choose to run our broker in a container environment, we may want to mount in the config files independently of the broker/container. The default setting is: 32 | 33 | 34 | 35 | The `bootstrap.xml` file also designates what applications are installed on the webserver that hosts the management console for our broker. We can configure details about this server (where it binds to, etc) as well as what application are exposed. Have a look at the `bootstrap.xml` file for more details and default configuration. 36 | 37 | Lastly, we can specify the bootstrap security configurations, like the JAAS domain name. 38 | 39 | ### broker.xml 40 | 41 | The most important configuration file is the `broker.xml` file. We'll cover some of the specifics of these configuration settings in subsequent labs, but just be aware, the major sections of configuration: 42 | 43 | * persistence 44 | * security 45 | * acceptors 46 | * addresses 47 | 48 | #### Configuration Reload 49 | 50 | Often times we'd like to make changes to the broker while it's running without taking the broker down. For some certain configurations, we're able to make changes at runtime while the broker is up and have those changes take effect. By default, every 5s the broker will poll its `broker.xml` configs and merge in changes it finds. The following sections are allowed to be changed at runtime (and will take effect upon change detection): 51 | 52 | * Security 53 | * Address settings 54 | * JMS Queues/Topics 55 | 56 | Note, if we were to remove addresses/queues, these would not be removed upon reload. This could introduce a scenario where we lose messages as a result. We can remove queues using the management features, but not by auto-reload. 57 | 58 | #### Persistence 59 | 60 | In the persistence section, we can configure whether we will use persistence (true/false), what type of journal impelemntation we'll use (NIO/AIO/JDBC) and the location on disk where the journals will be held for potentially different classes of messages (bindings, large-messages, main journal, etc). You can also tune the journal write buffers, number of files to keep etc, using this group of configuration settings. 61 | 62 | #### Security 63 | 64 | AMQ7 has fine grained Role Based Access Control for specifying what users can do when they connect and interact with addresses in the messaging system. Using the Security section of the `broker.xml` configuration file, we can assign roles to specific permissions such as `createDurableQueues` or `browse`, `send`, or `consume`, etc. 65 | 66 | #### Acceptors 67 | 68 | Acceptors are the "window" into the broker and is what clients connect to. Using acceptors we can expose different protocols on different ports, configure things like SSL/TLS and associated keystores, etc. If you look at the configuration for the `` section in the `broker.xml` file, you'll see something similar to this: 69 | 70 | ``` 71 | 72 | 73 | 74 | tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300 75 | 76 | 77 | tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpMinCredits=300 78 | 79 | 80 | tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true 81 | 82 | 83 | tcp://0.0.0.0:5445?protocols=HORNETQ,STOMP;useEpoll=true 84 | 85 | 86 | tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true 87 | 88 | 89 | 90 | ``` 91 | 92 | For example, to connect as an AMQP client, you'd configure your client to connect on port `5672` which is the default AMQP port. Alternatively, as you can see, there is a single acceptor that's capable of detecting and serving multiple protocols that listens on port `61616`. An AMQP (or STOMP, etc) client could also connect to this port. 93 | 94 | #### Addresses 95 | 96 | Lastly, the `` and `` section of the configuration define more granular properties for sets of destinations defined as *addresses*. In AMQ7, an *address* is an abstraction of any physical destination (actually, it can be many destinations). An *address* has a name, 0 or more destinations, and a routing type, of which that can be: 97 | 98 | 99 | | Routing Type | Description | 100 | |---|---| 101 | | Anycast | Deliver messages in a point-to-point manner | 102 | | Multicast | Deliver messages to all consumers in a group | 103 | 104 | We can associate an address with 0 or more physical queues. By default, AMQ7 configuration has the following addresses configured: 105 | 106 | ``` 107 | 108 |

109 | 110 | 111 | 112 |
113 |
114 | 115 | 116 | 117 |
118 | 119 | ``` 120 | 121 | ## Exercise 122 | 123 | In this lab, we're going to do two things: 124 | 125 | 1. Remove all of the `acceptors` except the default one on port `61616` which can handle all protocols 126 | 2. Add a new address and route it to a queue 127 | 128 | First, make sure your broker is stopped. In the previous lab we started the broker in the foreground; if it's still running, do a CTRL+C (^C) to gracefully bring it down. 129 | 130 | 131 | ### 1. Remove all acceptors 132 | Now, using your favorite text editor, open the `etc/broker.xml` file and find the section for the `acceptors`: 133 | 134 | ``` 135 | 136 | 137 | 138 | tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300 139 | 140 | 141 | tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpMinCredits=300 142 | 143 | 144 | tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true 145 | 146 | 147 | tcp://0.0.0.0:5445?protocols=HORNETQ,STOMP;useEpoll=true 148 | 149 | 150 | tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true 151 | 152 | 153 | 154 | ``` 155 | 156 | Delete all of the acceptors **except** the one listening on port `61616`. Your configuration for `acceptors` should look like this: 157 | 158 | ``` 159 | 160 | 161 | 162 | tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300 163 | 164 | 165 | 166 | ``` 167 | 168 | Now start up your broker in the foreground like we did in the previous lab: 169 | 170 | ./bin/artemis run 171 | 172 | When the broker starts up, you should see ONLY the single acceptor in the logs (see below). You will see logs saying protocol modules have been found, but that's OKAY. 173 | 174 | ![Single acceptor started up](images/configuration/startup.png) 175 | 176 | 177 | ### 2. Add a new address 178 | 179 | Now that our broker is running, let's try adding a new address and watch it reload the configuration automatically. Fire up your favorite editor again and edit the `etc/broker.xml` file. 180 | 181 | Add the following section to the `addresses` section: 182 | 183 | ``` 184 |
185 | 186 | 187 | 188 |
189 | ``` 190 | 191 | The configuration should look like this once edited: 192 | 193 | ``` 194 | 195 |
196 | 197 | 198 | 199 |
200 |
201 | 202 | 203 | 204 |
205 |
206 | 207 | 208 | 209 |
210 |
211 | ``` 212 | 213 | Now save your configuration file, wait at most 5s (the default refresh scan) and watch the broker logs to see if any changes have been detected: 214 | 215 | You should see something similar to the following: 216 | 217 | ``` 218 | 15:39:33,873 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...security 219 | 15:39:33,875 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...address settings 220 | 15:39:33,875 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...diverts 221 | 15:39:33,875 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...addresses 222 | 15:39:33,879 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue foo 223 | 15:39:33,887 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue DLQ 224 | 15:39:33,887 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue ExpiryQueue 225 | 226 | ``` 227 | 228 | That completes this lab! To see more in depth, follow the [product documentation on the Red Hat Customer Support portal](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/basic_configuration#configuration_files_and_locations) 229 | -------------------------------------------------------------------------------- /labs/100-brokerless.md: -------------------------------------------------------------------------------- 1 | # Brokerless routing 2 | 3 | Although the Interconnect Router can be used to build large-scale, geographically distributed broker clusters, it also provides a mechanism to do inter-network RPC against a transparent backplane where producers and consumers are decoupled in location (just like with a broker, but without a broker). This gives some of the best of both the messaging and RPC worlds. Let's take a look. 4 | 5 | 6 | In this lab we'll take a look at configuring the Interconnect Router to route messages to and from an AMQ7 broker. Clients can talk directly to the router and think they're talking to a broker. 7 | 8 | Take a look in the `labs/qdr/brokerless` folder. We have three different Interconnect configuration files and a couple different scripts to control the demo. We'll be using docker to run this demo, so verify you have access to a docker host (either on your laptop with Docker for Mac/Windows, or using Minikube, or using Red Hat CDK 3.0). 9 | 10 | 11 | Let's take a look at the salient parts of the configuration: 12 | 13 | router3.conf: 14 | 15 | ```json 16 | listener { 17 | role: normal 18 | host: 0.0.0.0 19 | port: 5672 20 | linkCapacity: 1000 21 | } 22 | 23 | ... 24 | 25 | listener { 26 | role: inter-router 27 | host: 0.0.0.0 28 | port: 10003 29 | } 30 | 31 | ``` 32 | 33 | Here we see that we're opening a listener for port `5672` and for `10003`. The `5672` port is for AMQP clients to connect directly to the router mesh. Port `10003` is for other routers to connect. Note the `role` each listener has (ie, `normal` and `inter-router`). We would expect the other routers to connect to this router via is listener on `10003`. Also, this router doesn't have any connectors to any other routers. 34 | 35 | router2.conf: 36 | 37 | ```json 38 | listener { 39 | role: inter-router 40 | host: 0.0.0.0 41 | port: 10002 42 | } 43 | 44 | ... 45 | 46 | connector { 47 | role: inter-router 48 | host: router3 49 | port: 10003 50 | saslMechanisms: ANONYMOUS 51 | } 52 | 53 | ``` 54 | 55 | In this configuration file, we see that there are *no* AMQP listeners (nothing listening on `5672`, and no listeners labeled `normal`). There is a single listener on port `10002`. We do see a single connector pointing to the router3 `10003` port. Let's look at the last router: 56 | 57 | router1.conf: 58 | 59 | ```json 60 | 61 | listener { 62 | role: normal 63 | host: 0.0.0.0 64 | port: 5672 65 | linkCapacity: 1000 66 | } 67 | 68 | 69 | ... 70 | 71 | connector { 72 | role: inter-router 73 | host: router2 74 | port: 10002 75 | saslMechanisms: ANONYMOUS 76 | } 77 | 78 | connector { 79 | role: inter-router 80 | host: router3 81 | port: 10003 82 | saslMechanisms: ANONYMOUS 83 | } 84 | 85 | ``` 86 | 87 | In this configuration, we see that this router also exposes an AMQP port on `5672`. It also connects to the other routers, router 2 on port `10002` and router 3 on `10003` 88 | 89 | Now that we see how the routers are connected with each other, let's bootstrap the router mesh. Make sure you're in the `labs/qdr/brokerless` folder and type: 90 | 91 | ```bash 92 | ./start.sh 93 | ``` 94 | 95 | This will bootstrap each broker with their respective configuration files and link them together properly. The containers will be running in the background, so you can take a look at each ones logs to verify they're up correctly: 96 | 97 | ```bash 98 | docker logs router1 99 | 4area\xa1\x010" 100 | Thu May 25 13:42:50 2017 ROUTER_CORE (trace) Core action 'delete_delivery' 101 | Thu May 25 13:42:50 2017 ROUTER_CORE (trace) Core action 'delete_delivery' 102 | Thu May 25 13:42:50 2017 ROUTER_CORE (trace) Core action 'link_flow' 103 | Thu May 25 13:42:50 2017 ROUTER_CORE (trace) Core action 'link_flow' 104 | Thu May 25 13:42:50 2017 SERVER (trace) [2]:1 <- @flow(19) [next-incoming-id=2600, incoming-window=2147483647, next-outgoing-id=0, outgoing-window=2147483647, handle=0, delivery-count=2600, link-credit=250, drain=false] 105 | Thu May 25 13:42:50 2017 SERVER (trace) [2]:0 <- @transfer(20) [handle=0, delivery-id=2604, delivery-tag=b"X\x14\x00\x00\x00\x00\x00\x00", message-format=0, settled=true, more=false] (229) "\x00Sr\xd1\x00\x00\x00E\x00\x00\x00\x04\xa3\x0ex-opt-qd.trace\xd0\x00\x00\x00\x0f\x00\x00\x00\x01\xa1\x090/Router3\xa3\x10x-opt-qd.ingress\xa1\x090/Router3\x00Ss\xd0\x00\x00\x00\x1f\x00\x00\x00\x06@@\xa1\x14amqp:/_local/qdhello@@@\x00St\xd1\x00\x00\x00\x13\x00\x00\x00\x02\xa1\x06opcode\xa1\x05HELLO\x00Sw\xd1\x00\x00\x00N\x00\x00\x00\x08\xa1\x04seen\xd0\x00\x00\x00\x16\x00\x00\x00\x02\xa1\x07Router2\xa1\x07Router1\xa1\x08instance\x81\x00\x00\x00\x00Y&\xd5\xd9\xa1\x02id\xa1\x07Router3\xa1\x04area\xa1\x010" 106 | 107 | ``` 108 | 109 | To run the demo, make sure you start a receiver first: 110 | 111 | ```bash 112 | ./receiver_router3.sh 113 | ``` 114 | 115 | This will connect to router 3 on its AMQP port (`5672`) and begin listening for messages on address `/myAddress`. 116 | 117 | Let's start the sender: 118 | 119 | ```bash 120 | ./sender_router1.sh 121 | ``` 122 | 123 | This will connect to the router 1 on its AMQP port and send messages to address `/myAddress`. You should see indications of a single message flowing through the mesh (via the sender/receiver logs). 124 | -------------------------------------------------------------------------------- /labs/110-enmasse.md: -------------------------------------------------------------------------------- 1 | # Messaging as a Service with Enmasse 2 | 3 | Red Hat AMQ Online is a new Messaging as a Service (MaaS) offering built on OpenShift. It offers a self-service approach to managing brokers, giving developers the ability to create and manage their own queues and topics. This lab steps you through this process using the technical preview environment from Red Hat. 4 | 5 | To get started: 6 | 7 | 1. Request an Red Hat AMQ Online account by [email](amq-online-tech-preview-owner@redhat.com). 8 | 2. Login to Enmasse using the credentials given in the response email. Ensure you can login and view the Dashboard 9 | 3. Click on "Addresses", then click "Create". Create a new address called "queue" using the standard plan 10 | 4. Git clone the qpid-jms project from [here](https://github.com/apache/qpid-jms) to a local directory 11 | 5. Update the `jndi.properties` file located in `qpid-jms-examples/src/main/resources/jndi.properties` with the following: 12 | 13 | ``` 14 | connectionfactory.myFactoryLookup = amqps://?transport.trustAll=true&transport.verifyHost=false 15 | queue.myQueueLookup = queue 16 | ``` 17 | 6. Via the command line, execute the following command in the `qpid-jms-examples` directory: 18 | 19 | ``` 20 | java -cp "target/classes/:target/dependency/*" -DUSER="" -DPASSWORD="" org.apache.qpid.jms.example.Sender 21 | ``` 22 | 7. Check the Enmasse dashboard and it's been updated with the messages sent to "queue". You should see "10 messages sent". 23 | 8. Via the command line, execute the following command to consume the messages: 24 | 25 | ``` 26 | java -cp "target/classes/:target/dependency/*" -DUSER="" -DPASSWORD="" org.apache.qpid.jms.example.Receiver 27 | ``` 28 | 9. The metrics in the Dashboard should be updated with 10 messages sent / received 29 | -------------------------------------------------------------------------------- /labs/20-clients.md: -------------------------------------------------------------------------------- 1 | # AMQ 7 Clients 2 | 3 | AMQ 7 comes with several new clients covering a variety of protocols and programming languages. In the past, any supported clients were only released when we released new versions of the AMQ product. With AMQ7 that has changed; each client has its own lifecycle and is released independently from the AMQ broker/server components. 4 | 5 | AMQ7 includes the following supported clients: 6 | 7 | * AMQ JMS Client ([official docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_jms_client/)) 8 | * AMQ C++ Client ([official docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_cpp_client/)) 9 | * AMQ JavaScript/NodeJS Client ([official docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_javascript_client/)) 10 | * AMQ Python Client ([official docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_python_client/)) 11 | * AMQ .NET Client ([official docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_.net_client/)) 12 | 13 | Let's explore the clients. 14 | 15 | ## AMQ JMS Client 16 | 17 | To use the AMQ JMS client, navigate to [https://developers.redhat.com/products/amq/download/](https://developers.redhat.com/products/amq/download/) and locate the AMQ JMS Client. 18 | 19 | ![Download JMS](images/client/download-jms-client.png) 20 | 21 | When you've downloaded the file, copy it to a location where you'd like to unzip this client. 22 | 23 | $ mv ~/Downloads/apache-qpid-jms-0.21.0.redhat-1-bin.zip ./clients/ 24 | $ cd clients 25 | $ unzip apache-qpid-jms-0.21.0.redhat-1-bin.zip 26 | $ cd apache-qpid-jms-0.21.0.redhat-1 27 | 28 | 29 | Now we'll explore the client. In the distribution we just unzipped, there's an `examples` folder. Navigate into it and you'll find a Java Maven project. Let's build the project: 30 | 31 | 32 | $ cd examples 33 | $ mvn -s example-settings.xml install 34 | 35 | If successful, you should see output like this: 36 | 37 | ``` 38 | [INFO] 39 | [INFO] --- maven-install-plugin:2.5.2:install (default-install) @ qpid-jms-examples --- 40 | [INFO] Skipping artifact installation 41 | [INFO] ------------------------------------------------------------------------ 42 | [INFO] BUILD SUCCESS 43 | [INFO] ------------------------------------------------------------------------ 44 | [INFO] Total time: 4.063 s 45 | [INFO] Finished at: 2017-05-11T15:52:15-07:00 46 | [INFO] Final Memory: 28M/456M 47 | [INFO] ------------------------------------------------------------------------ 48 | ``` 49 | 50 | Feel free to open this project in your favorite IDE (like [JBoss Developer Studio](https://developers.redhat.com/products/devstudio/overview/)). 51 | 52 | A couple of things to notice about this example: 53 | 54 | * Our JMS ConnectionFactory and destination names are configured in the `src/main/resources/jndi.properties` file 55 | * Our `org.apache.qpid.jms.example.HelloWorld` main() class bootstraps the `MessageConsumer` and `MessageProducer` used in this example 56 | * We lookup the JMS connection information from JNDI as specified in our `jndi.properties` file 57 | * We send one message and receive one message. 58 | 59 | Review the code closer to get an idea of what it's doing: 60 | 61 | ```java 62 | public static void main(String[] args) throws Exception { 63 | try { 64 | // The configuration for the Qpid InitialContextFactory has been supplied in 65 | // a jndi.properties file in the classpath, which results in it being picked 66 | // up automatically by the InitialContext constructor. 67 | Context context = new InitialContext(); 68 | 69 | ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup"); 70 | Destination queue = (Destination) context.lookup("myQueueLookup"); 71 | 72 | Connection connection = factory.createConnection(System.getProperty("USER"), System.getProperty("PASSWORD")); 73 | connection.setExceptionListener(new MyExceptionListener()); 74 | connection.start(); 75 | 76 | Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 77 | 78 | MessageProducer messageProducer = session.createProducer(queue); 79 | MessageConsumer messageConsumer = session.createConsumer(queue); 80 | 81 | TextMessage message = session.createTextMessage("Hello world!"); 82 | messageProducer.send(message, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE); 83 | TextMessage receivedMessage = (TextMessage) messageConsumer.receive(2000L); 84 | 85 | if (receivedMessage != null) { 86 | System.out.println(receivedMessage.getText()); 87 | } else { 88 | System.out.println("No message received within the given timeout!"); 89 | } 90 | 91 | connection.close(); 92 | } catch (Exception exp) { 93 | System.out.println("Caught exception, exiting."); 94 | exp.printStackTrace(System.out); 95 | System.exit(1); 96 | } 97 | } 98 | ``` 99 | 100 | To run this example, we'll first download all of the project's dependencies: 101 | 102 | $ mvn -s example-settings.xml clean package dependency:copy-dependencies -DincludeScope=runtime -DskipTests 103 | 104 | Next, we need to make sure our broker is running. If you've followed from the previous labs, you have a broker running with a single `Acceptor` running on port `61616`. Let's change our `jndi.properties` file to reflect this change. (if you're coming to this lab from your own installation/running instance of the AMQ7 broker, adjust the properties as needed; e.g., if you still have the dedicated AMQP `Acceptor` running, then no need to make this change). 105 | 106 | Our `jndi.properties` file should look like this, with the `connectionfactory.myFactoryLookup` property set to `61616` 107 | 108 | NOTE: We need to change the connection factory URL to `61616` since our `acceptor` does not have the other ports open. 109 | 110 | ``` 111 | # Set the InitialContextFactory class to use 112 | java.naming.factory.initial = org.apache.qpid.jms.jndi.JmsInitialContextFactory 113 | 114 | # Define the required ConnectionFactory instances 115 | # connectionfactory. = 116 | connectionfactory.myFactoryLookup = amqp://localhost:61616 117 | 118 | # Configure the necessary Queue and Topic objects 119 | # queue. = 120 | # topic. = 121 | queue.myQueueLookup = queue 122 | topic.myTopicLookup = topic 123 | ``` 124 | 125 | Now let's build our project and run: 126 | 127 | $ mvn -s example-settings.xml clean install 128 | $ mvn -s example-settings.xml clean package dependency:copy-dependencies -DincludeScope=runtime -DskipTests 129 | $ java -cp "target/classes/:target/dependency/*" org.apache.qpid.jms.example.HelloWorld 130 | 131 | If everything completed properly, you should see the following output: 132 | 133 | ``` 134 | Hello world! 135 | ``` 136 | 137 | #### Some things to note: 138 | 139 | The URL we passed to the connection factory should be in the following form: 140 | 141 | > amqp[s]://hostname:port[?option=value[&option2=value...]] 142 | 143 | We can also use the failover URI (discussed in future lab) like this: 144 | 145 | > failover:(amqp://host1:port[,amqp://host2:port...])[?option=value[&option2=value...]] 146 | 147 | Options for configuration can be [found at the AMQ7 JMS Client product documentation](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_the_amq_jms_client/configuration#connection_uri_options_jms) 148 | 149 | 150 | ## AMQ NodeJS Client 151 | 152 | The AMQ NodeJS client can be used to connect to the AMQ7 broker (or any compatible AMQP 1.0 broker) and can send and receive messages regardless of what clients produced them (ie, they could be MQTT IoT producers for example). 153 | 154 | To use the AMQ NodeJS client, navigate to [https://developers.redhat.com/products/amq/download/](https://developers.redhat.com/products/amq/download/) and locate the AMQ NodeJS (called "JavaScript" in the download portal) Client. 155 | 156 | ![Download JMS](images/client/download-node-client.png) 157 | 158 | When you've downloaded the file, copy it to a location where you'd like to unzip this client. 159 | 160 | $ mv ~/Downloads/nodejs-rhea-0.2.0-1.zip . ./clients/ 161 | $ cd clients 162 | $ unzip nodejs-rhea-0.2.0-1.zip 163 | $ cd nodejs-rhea-0.2.0-1 164 | 165 | To run the examples, we'll need to install two dependencies: 166 | 167 | $ npm install debug 168 | $ npm install yargs 169 | 170 | Now let's navigate to the `examples` folder and take a look at the application that will receive messages from the broker: 171 | 172 | $ cd node_modules/rhea/examples 173 | 174 | Open up the `simple_recv.js` file in your favorite editor: 175 | 176 | ```js 177 | var args = require('yargs').options({ 178 | 'm': { alias: 'messages', default: 100, describe: 'number of messages to expect'}, 179 | 'n': { alias: 'node', default: 'examples', describe: 'name of node (e.g. queue) from which messages are received'}, 180 | 'p': { alias: 'port', default: 5672, describe: 'port to connect to'} 181 | }).help('help').argv; 182 | 183 | var received = 0; 184 | var expected = args.messages; 185 | 186 | container.on('message', function (context) { 187 | if (context.message.id && context.message.id < received) { 188 | // ignore duplicate message 189 | return; 190 | } 191 | if (expected === 0 || received < expected) { 192 | console.log(JSON.stringify(context.message.body)) 193 | if (++received === expected) { 194 | context.receiver.detach(); 195 | context.connection.close(); 196 | } 197 | } 198 | }); 199 | 200 | container.connect({'port':args.port}).open_receiver(args.node); 201 | ``` 202 | 203 | 204 | We see that this simple receiver application tries to connect to a broker on port `5672` by default (which is also the AMQP default port) and tries to read messages from the `examples` queue. Since we have our broker running on port `61616`, let's run our receiver and direct it to connect to our broker on the correct port: 205 | 206 | $ node simple_recv.js -p 61616 207 | 208 | Open another window to run our sender. Navigate back to the same directory where the examples where and run: 209 | 210 | $ node simple_send.js -p 61616 211 | 212 | Note that for the sender, we're also changing its port. Hit enter to run the sender. You should see similar output: 213 | 214 | From the receiver: 215 | 216 | ``` 217 | {"sequence":1} 218 | . 219 | . 220 | . 221 | {"sequence":90} 222 | {"sequence":91} 223 | {"sequence":92} 224 | {"sequence":93} 225 | {"sequence":94} 226 | {"sequence":95} 227 | {"sequence":96} 228 | {"sequence":97} 229 | {"sequence":98} 230 | {"sequence":99} 231 | {"sequence":100} 232 | ``` 233 | 234 | From the sender: 235 | 236 | ``` 237 | sent 1 238 | . 239 | . 240 | . 241 | sent 90 242 | sent 91 243 | sent 92 244 | sent 93 245 | sent 94 246 | sent 95 247 | sent 96 248 | sent 97 249 | sent 98 250 | sent 99 251 | sent 100 252 | all messages confirmed 253 | ``` 254 | 255 | 256 | 257 | 258 | ## Other clients 259 | 260 | You can download the other clients from the Red Hat support portal or the developers.redhat.com site. At the moment all the clients are available for download there EXCEPT the *Python* and *Linux C++* libraries (for RHEL). Those are available as RPMs through your RHEL subscription. 261 | -------------------------------------------------------------------------------- /labs/30-produce-consume.md: -------------------------------------------------------------------------------- 1 | # Producing and Consuming 2 | 3 | AMQ7 has many features. We are going to work through a couple of those features, but at the end of this lab you should feel comfortable with some of the basics. We'll leave suggestions at the end for where to learn more about the other features not covered in this lab. 4 | 5 | ## Use cases: 6 | 7 | * Send messages to the broker 8 | * Receive messages from the broker 9 | * Request Reply 10 | * Dead Letter Queue (DLQ) 11 | * Last Value queue 12 | 13 | 14 | ## Before we begin 15 | 16 | In the previous labs we've installed and configured our broker. We eliminated the individual ports/protocols and are happy to have all protocols go through the default `Acceptor` at port `61616`. For the remainder of this section, please verify that your broker is running and able to take connections. Each of the next sections assumes this is the case. 17 | 18 | ### Send 19 | Let's look at how to easily send and consume messages from a queue. In the [previous lab](./20-clients.md), we explored some of the client APIs. How we send messages to the broker will depend on what programming language and API you wish to use. But what if you just want to quickly test whether the broker is up? Or that some configuration you changed is working as expcted? What if you just want to send some sample load to the broker and don't want to build a producer/client from scratch? Luckily, Artemis comes with some tools for exploring these scenarios. 20 | 21 | You should have your `myfirstbroker` running with: 22 | 23 | ```bash 24 | $ ./bin/artemis run 25 | ``` 26 | 27 | This should give you a broker running in the foreground. 28 | 29 | In a different window try running the following command: 30 | 31 | ```bash 32 | $ ./bin/artemis help producer 33 | ``` 34 | 35 | 36 | This should show a help guide for how to use a simple producer to send messages to the AMQ7 broker. 37 | 38 | Let's try sending messages: 39 | 40 | ```bash 41 | $ ./bin/artemis producer --destination address.helloworld --message-count 100 --url tcp://localhost:61616 42 | ``` 43 | 44 | 45 | 46 | If we [go to the Broker web console](http://localhost:8161/hawtio) at [http://localhost:8161/hawtio](http://localhost:8161/hawtio) we should see that we now have `100` messages in the `foo` queue. Remember from the first lab, we created a new address called `address.helloworld` and bound it as an `Anycast` address to the `foo` queue. 47 | 48 | > Note: use the credentials you set when we created the broker; admin/admin 49 | 50 | ![](images/produce-consume/producer-message-count.png) 51 | 52 | Let's use the same tools to consume messages. 53 | 54 | ### Receive 55 | 56 | Let' use the same CLI tools to simulate consumption from addresses on the broker. Let's try to consume from the same address `address.helloworld` -- but let's not consume all the messages. Let's start by consuming `50` of the messages. Just like in the previous section, we want to make sure the broker is up and running and listening on port `61616`. In a separate window, let's take a look at the parameters for the `consumer` command: 57 | 58 | ```bash 59 | $ ./bin/artemis help consumer 60 | ``` 61 | 62 | Now let's try to consume 50 messages from the `foo` queue (remember, our `Anycast` address was bound to `foo`): 63 | 64 | ```bash 65 | $ ./bin/artemis consumer --destination foo --message-count=50 --url tcp://localhost:61616 66 | ``` 67 | 68 | You should get output similar to this: 69 | 70 | ```bash 71 | Consumer:: filter = null 72 | Consumer ActiveMQQueue[foo], thread=0 wait until 50 messages are consumed 73 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 0 74 | . 75 | . 76 | . 77 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 39 78 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 40 79 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 41 80 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 42 81 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 43 82 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 44 83 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 45 84 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 46 85 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 47 86 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 48 87 | Consumer ActiveMQQueue[foo], thread=0 Received test message: 49 88 | ``` 89 | 90 | 91 | So now if we look at our console, we should see that `50` messages are still left on our queue `foo`: 92 | 93 | ![Consumed 50](images/produce-consume/consume-50.png) 94 | 95 | No go find where your broker is running and let's kill the broker. If we try to consume from the broker at this point, we should see that we cannot establish a connection. When we restart the broker, we exepct our messages to still be on the broker and availabe for consumption. Let's fire up the broker again: 96 | 97 | ```bash 98 | $ ./bin/artemis run 99 | ``` 100 | 101 | Navigate back to the web console and verify we still have `50` messages on the queue `foo`. 102 | 103 | Let's consume the last `50` messages: 104 | 105 | ```bash 106 | $ ./bin/artemis consumer --destination foo --message-count=50 --url tcp://localhost:61616 107 | ``` 108 | 109 | And we should see our queue is now empty: 110 | 111 | ![Consumed 50](images/produce-consume/consumer-drain.png) 112 | 113 | 114 | ### Request Reply 115 | 116 | Messaging is typically used to decouple producers and consumers in two main dimensions: time, and space. When will a consumer see messages? Who knows, but it's not the producer's responsibility. Where do the consumers even live? Again, not a detail a producer should be coupled to. However, there are use cases where producing messages/events will necessitate a response from *some* consumer downstream. You may already have usecases implemented like this using some legacy proprietary queuing system and would like a nice replacement for that legacy system but cannot change your application. However you come across a request-reply usecase here's what it looks like with JBoss AMQ7. 117 | 118 | In the root of the AMQ7 broker installation, there is an `examples` folder. There are a handful of nice examples here. Navigate to: 119 | 120 | ```bash 121 | $ cd $AMQ7_BASE/examples/features/standard/request-reply 122 | ``` 123 | 124 | Copy the example-settings.xml you used in previous labs to the request-reply directory. Let's run the example. Note, just like in the previous sections, we need to have a broker running: 125 | 126 | ```bash 127 | $ mvn -s example-settings.xml verify -DnoServer=true 128 | ``` 129 | 130 | We should see an output like this: 131 | 132 | ```bash 133 | [INFO] --- artemis-maven-plugin:2.0.0.amq-700005-redhat-1:runClient (runClient) @ request-reply --- 134 | Request message sent. 135 | Received request message: A request message 136 | Reply to queue: ActiveMQTemporaryQueue[d6677193-fef2-4fee-9f8b-d84b08eaff37] 137 | Reply sent 138 | Received reply: A reply message 139 | CorrelatedId: ID:76c9b485-39ba-11e7-b79b-0a0027000003 140 | We found matched request: A request message 141 | [INFO] 142 | [INFO] --- artemis-maven-plugin:2.0.0.amq-700005-redhat-1:cli (stop) @ request-reply --- 143 | [INFO] ------------------------------------------------------------------------ 144 | [INFO] BUILD SUCCESS 145 | [INFO] ------------------------------------------------------------------------ 146 | [INFO] Total time: 4.427 s 147 | [INFO] Finished at: 2017-05-15T15:04:27-07:00 148 | [INFO] Final Memory: 37M/457M 149 | [INFO] ------------------------------------------------------------------------ 150 | ``` 151 | 152 | So what happened here? We sent a message to a queue and got a response. But what does this look like? 153 | 154 | If you open the `Java` source file in the `request-reply` project `src/main/java//org/apache/activemq/artemis/jms/example/RequestReplyExample.java` we can see a little about how this happens. 155 | 156 | First we set up the connection-factory infromation and make a connection to the broker. Then we do the following: 157 | 158 | 1. Set up the producer 159 | 160 | For this, we create a producer to the "request queue" but we also create a temporary destination and attach a consumer to that temporary destination. This simulates the producer sending a message and also waiting for a response on the temporary destination: 161 | 162 | ```java 163 | MessageProducer producer = session.createProducer(requestQueue); 164 | 165 | TemporaryQueue replyQueue = session.createTemporaryQueue(); 166 | 167 | MessageConsumer replyConsumer = session.createConsumer(replyQueue); 168 | ``` 169 | 170 | Next, we create our message and send it. Before we send it, however, we set a JMS property to specify where the response should be sent. It should, of course, be sent to our temporary destination like we are expecting: 171 | 172 | ```java 173 | TextMessage requestMsg = session.createTextMessage("A request message"); 174 | 175 | requestMsg.setJMSReplyTo(replyQueue); 176 | 177 | producer.send(requestMsg); 178 | ``` 179 | 180 | We should optionally try to coordinate/correlate the response when it comes back to us. We'll save the message ID or some correlation ID that we specify: 181 | 182 | ```java 183 | requestMap.put(requestMsg.getJMSMessageID(), requestMsg); 184 | ``` 185 | 186 | 2. Set up the consumer 187 | 188 | On the consumer side, we should consume the message like normal (either using a `receive` method or `onMessage` listener) but also check the `ReplyTo` header. We should generate a response and send that response to the destination specified in the `ReplyTo` header: 189 | 190 | 191 | ```java 192 | public void onMessage(final Message request) { 193 | try { 194 | System.out.println("Received request message: " + ((TextMessage) request).getText()); 195 | 196 | // Extract the ReplyTo destination 197 | Destination replyDestination = request.getJMSReplyTo(); 198 | 199 | System.out.println("Reply to queue: " + replyDestination); 200 | 201 | // Create the reply message 202 | TextMessage replyMessage = session.createTextMessage("A reply message"); 203 | 204 | // Set the CorrelationID, using message id. 205 | replyMessage.setJMSCorrelationID(request.getJMSMessageID()); 206 | 207 | // Send out the reply message 208 | replyProducer.send(replyDestination, replyMessage); 209 | 210 | System.out.println("Reply sent"); 211 | } catch (JMSException e) { 212 | e.printStackTrace(); 213 | } 214 | } 215 | ``` 216 | 217 | 218 | ### Dead Letter Queue 219 | 220 | What happens when a consumer cannot process a message? Or what happens when a transaction is rolled back? A JMS message in the AMQ7 broker will be redelivered (and possibly to other consumers) if a consumer is having trouble with it. The problem is, we cannot just redeliver for ever because it will starve other consumers and messages it that come later in the queue. To deal with this, we can send the non-consumable message to the "dead letter queue". 221 | 222 | First, we'll need to configure the broker for dead-letter queue (DLQ) behavior. Let's open our `myfirstbroker` configuration file in `etc/broker.xml` and navigate to the `address-settings` location. We should see an entry similar to this: 223 | 224 | ```xml 225 | 226 | DLQ 227 | ExpiryQueue 228 | 0 229 | 230 | -1 231 | 10 232 | PAGE 233 | true 234 | true 235 | true 236 | true 237 | 238 | ``` 239 | 240 | This configuration sets up a "dead-letter queue" for "#" (which is all, recursive) destinations set to a value of `DLQ`. If you look in the web console, you'll see a queue named `DLQ`. 241 | 242 | By default, the max number of retries is `10` but for this lab, we want to change it to a smaller number. Let's change it to `3` by adding a configuration `3` to our `address-settings`. Your config should look like this: 243 | 244 | ```xml 245 | 246 | DLQ 247 | 3 248 | ExpiryQueue 249 | 0 250 | 251 | -1 252 | 10 253 | PAGE 254 | true 255 | true 256 | true 257 | true 258 | 259 | ``` 260 | 261 | Now save your `broker.xml` file. If you had your broker running while you made the change, you should see the configuration auto-reload with a message similar to this in the broker logs: 262 | 263 | ```bash 264 | 15:26:47,336 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...security 265 | 15:26:47,339 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...address settings 266 | 15:26:47,340 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...diverts 267 | 15:26:47,340 INFO [org.apache.activemq.artemis.core.server] AMQ221056: Reloading configuration ...addresses 268 | 15:26:47,351 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue foo 269 | 15:26:47,352 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue DLQ 270 | 15:26:47,352 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue ExpiryQueue 271 | ``` 272 | 273 | Now, let's go to the `dead-letter` example from the examples that ship with the AMQ7 broker: 274 | 275 | ```bash 276 | $ cd $AMQ7_BASE/examples/features/standard/dead-letter 277 | ``` 278 | 279 | The example will try to consume messages a few times and try rolling them back 3 times to force the message to the `DLQ` queue. One thing we want to change: we want to configure out example to use `DLQ` as the dead-letter queue. To do this, let's open the `src/main/resources/jndi.properties` file dn change the `queue.queue/deadLetterQueue` to be `DLQ` 280 | 281 | Your file should look like this: 282 | 283 | ```java 284 | java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory 285 | connectionFactory.ConnectionFactory=tcp://localhost:61616 286 | queue.queue/exampleQueue=exampleQueue 287 | queue.queue/deadLetterQueue=DLQ 288 | ``` 289 | 290 | Let's run the example 291 | 292 | ```bash 293 | $ mvn verify -DnoServer=true 294 | ``` 295 | 296 | We should see output like this: 297 | 298 | ```bash 299 | Sent message to exampleQueue: this is a text message 300 | 1st delivery from exampleQueue: this is a text message 301 | 2nd delivery from exampleQueue: this is a text message 302 | 3rd delivery from exampleQueue: this is a text message 303 | 4th delivery from exampleQueue: null 304 | ``` 305 | 306 | If we check the `DLQ` queue in the web console, we can see that it now has one message in it: 307 | 308 | ![](images/produce-consume/dlq.png) 309 | 310 | ### Last Value queue 311 | 312 | A last-value queue is a special kind of queue that keeps only the most recent message for a specific type of message (defined by a `Last-Value` property). This could be useful for stock price updates where we really only care about the most recent updates. 313 | 314 | First, we'll need to configure the broker for last-value queue behavior for the destinations we define. We don't want all of our queues to be last-value, so we need to explicitly set up a specific queue. Let's open our `myfirstbroker` configuration file in `etc/broker.xml` and navigate to the `address-settings` location. We will add a configuration for a queue named `exampleQueue` to be a last-value queue: 315 | 316 | ```xml 317 | 318 | true 319 | 320 | ``` 321 | 322 | We will also add a new `Anycast` address and bind it to a queue named `exampleQueue`: 323 | 324 | ```xml 325 |
" 326 | 327 | 328 | 329 |
330 | ``` 331 | 332 | 333 | Now, let's go to the `last-value-queue` example from the examples that ship with the AMQ7 broker: 334 | 335 | ```bash 336 | $ cd $AMQ7_BASE/examples/features/standard/last-value-queue 337 | ``` 338 | 339 | Let's run the example 340 | 341 | ```bash 342 | $ mvn verify -DnoServer=true 343 | ``` 344 | 345 | We should see output like this: 346 | 347 | ```bash 348 | [INFO] --- artemis-maven-plugin:2.0.0.amq-700005-redhat-1:runClient (runClient) @ last-value-queue --- 349 | Sent message: 1st message with Last-Value property set 350 | Sent message: 2nd message with Last-Value property set 351 | Sent message: 3rd message with Last-Value property set 352 | Message in the queue: 3rd message with Last-Value property set 353 | Received message: 3rd message with Last-Value property set 354 | Received message: null 355 | ``` 356 | 357 | Let's take a closer look at what's going on. 358 | 359 | If you open the `Java` source file in the `last-value-queue` project `src/main/java//org/apache/activemq/artemis/jms/example/LastValueQueueExample.java` we can see a little about how this happens. 360 | 361 | When we send messages to the `exampleQueue` queue (which was earlier configured for Last Value semantics), we are adding a JMS property named `_AMQ_LVQ_NAME` which is the field that the last-value queue implementation will match on: 362 | 363 | ```java 364 | TextMessage message = session.createTextMessage("1st message with Last-Value property set"); 365 | message.setStringProperty("_AMQ_LVQ_NAME", "STOCK_NAME"); 366 | producer.send(message); 367 | ``` 368 | 369 | If the queue sees multiple messages with the same `_AMQ_LVQ_NAME` property, then it will only keep the most recent message. The example sends in three messages with the same value (`_AMQ_LVQ_NAME1` equal to `STOCK_NAME`) and tries to consume from the `exampleQueue` queue. It finds only the 3rd message sent. 370 | 371 | 372 | 373 | ## Where to go from here 374 | 375 | Check out the examples in the distro 376 | -------------------------------------------------------------------------------- /labs/40-master-slave.md: -------------------------------------------------------------------------------- 1 | # Master/Slave - Shared Store 2 | 3 | A-MQ 7 has the ability to run in a master/slave (ie, active/passive) configuration so that if an active node goes down, another can immediately take its place and continue serving clients and processing messages. There are a few different options that can be used to achieve this: 4 | 5 | * Shared store 6 | * Replicated store (ie, "shared nothing") 7 | * Co-located 8 | 9 | For the purpose of this lab, we will focus on the "Shared store" option for persistence, and use the "Static" option for clustering. 10 | 11 | ## Prerequisites 12 | 13 | Download and install the A-MQ 7 broker package as described in [Lab 1](00-install-broker.md). 14 | 15 | ## Creating the brokers 16 | 17 | ``` 18 | $ $AMQ_HOME/bin/artemis create brokers/master --name master --user admin --password admin --allow-anonymous 19 | $ $AMQ_HOME/bin/artemis create brokers/slave --name slave --user admin --password admin --allow-anonymous --port-offset 1 20 | ``` 21 | 22 | _Note: We could have passed in some extra arguments to configure our master/slave pair with some defaults, but instead we're going to manually configure them via the `broker.xml` file so we can become familiar with the available options._ 23 | 24 | ## Editing the configuration 25 | 26 | __Master__ 27 | 28 | 1. Open up the `brokers/master/etc/broker.xml` file in your favorite text editor. 29 | 30 | 2. Modify the existing `paging-directory`, `bindings-directory`, `journal-directory`, and `large-messages-directory` elements to point to a shared mount. In the real world, this would likely point to a directory on a SAN that is mounted on both the master and slave machines. 31 | 32 | ```xml 33 | ../sharedstore/data/paging 34 | ../sharedstore/data/bindings 35 | ../sharedstore/data/journal 36 | ../sharedstore/data/large-messages 37 | ``` 38 | 39 | 3. Add the following elements anywhere under the `` element: 40 | 41 | ```xml 42 | 43 | tcp://localhost:61616 44 | tcp://localhost:61617 45 | 46 | 47 | admin 48 | admin 49 | 50 | 51 | 52 | master-connector 53 | 54 | slave-connector 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | true 63 | 64 | 65 | 66 | ``` 67 | 68 | 4. Start the broker: 69 | 70 | ``` 71 | $ ./brokers/node1/bin/artemis run 72 | ``` 73 | 74 | __Slave__ 75 | 76 | 1. Open up the `brokers/slave/etc/broker.xml` file in your favorite text editor. 77 | 78 | 2. Modify the existing `paging-directory`, `bindings-directory`, `journal-directory`, and `large-messages-directory` elements to point to a shared mount. In the real world, this would likely point to a directory on a SAN that is mounted on both the master and slave machines. 79 | 80 | ```xml 81 | ../sharedstore/data/paging 82 | ../sharedstore/data/bindings 83 | ../sharedstore/data/journal 84 | ../sharedstore/data/large-messages 85 | ``` 86 | 87 | 3. Add the following elements anywhere under the `` element: 88 | 89 | ```xml 90 | 91 | tcp://localhost:61616 92 | tcp://localhost:61617 93 | 94 | 95 | admin 96 | admin 97 | 98 | 99 | 100 | slave-connector 101 | 102 | master-connector 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | true 111 | true 112 | 113 | 114 | 115 | ``` 116 | 117 | 4. Start the broker: 118 | 119 | ``` 120 | $ ./brokers/node2/bin/artemis run 121 | ``` 122 | 123 | ## Testing 124 | 125 | 1. Open up a new terminal window and run the following command: 126 | 127 | ``` 128 | $ $AMQ_HOME/bin/artemis producer --verbose --user admin --password admin --message-count 100 --url 'tcp://localhost:61616' 129 | ``` 130 | 131 | 2. Shut down the master broker (ie, by hitting ctrl-c on its terminal). You should see the slave broker log a few messages indicating that it has come online (this might take a couple of seconds). 132 | 133 | 3. In the same terminal window that you ran the producer command, run the following command: 134 | 135 | ``` 136 | $ $AMQ_HOME/bin/artemis consumer --verbose --user admin --password admin --message-count 100 --url 'tcp://localhost:61617' 137 | ``` 138 | 139 | All of the messages that you produced to the master broker in step 1 should be consumed from the slave broker. 140 | 141 | 4. (optional) Restart the master broker and you should see that it will take over and the slave will shut down/go back into slave mode (this might take a couple of seconds). 142 | -------------------------------------------------------------------------------- /labs/50-replication.md: -------------------------------------------------------------------------------- 1 | # AMQ 7 Message Persistence & Replication 2 | 3 | AMQ7 has various message persistence options: 4 | 5 | * NIO (Java NIO, journal-based persistence) 6 | * ASYNCIO (Linux Asynchronous IO, journal-based persistence) 7 | * JDBC (persist to the relational database of your choice) 8 | * Memory (in-memory stateless message persistence) 9 | 10 | The default, out-of-the-box settin is NIO file journal-based persistence. You can configure message persistence by updating the `/jboss-amq-7.0.0.redhat-1/brokers/myfirstbroker/etc/broker.xml` file. Here is the section in `broker.xml`: 11 | 12 | ``` 13 | 14 | 15 | ... 16 | true 17 | 18 | NIO 19 | ./data/paging 20 | ./data/bindings 21 | ./data/journal 22 | ./data/large-messages 23 | true 24 | 2 25 | -1 26 | ... 27 | 28 | 29 | ``` 30 | 31 | For further details around message persistence, refer to the product documentation [here](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/basic_configuration#configuring_persistence). 32 | 33 | ## Replication 34 | 35 | The following lab demonstrates setting up a 2-node master / slave cluster with shared-nothing replication. 36 | 37 | ### Lab - Shared-nothing replication between Master / Slave cluster 38 | 39 | #### Prerequisites 40 | 41 | Download the legacy ActiveMQ client JAR which supports OpenWire failover [here](https://mvnrepository.com/artifact/org.apache.activemq/activemq-all/5.14.5) 42 | 43 | 1. Create a master and slave broker pair by running the following commands: 44 | 45 | ``` 46 | $ ./bin/artemis create brokers/master 47 | $ ./bin/artemis create brokers/slave --port-offset 1 48 | ``` 49 | 50 | Be sure to give each broker the `admin/admin` username / password combo and allow anonymous access. 51 | 52 | 2. Replace the etc/broker.xml file from the examples directory for both master and slave: 53 | 54 | ``` 55 | cp /jboss-amq-7.0.0.redhat-1/examples/features/clustered/clustered-static-discovery/src/main/resources/activemq/server0/broker.xml /brokers/master/etc/broker.xml 56 | cp /jboss-amq-7.0.0.redhat-1/examples/features/clustered/clustered-static-discovery/src/main/resources/activemq/server1/broker.xml /brokers/slave/etc/broker.xml 57 | ``` 58 | 3. Replace the security-settings section of both master / slave broker.xml files with the following text (this will allow the producer / consumer to dynamically create queues): 59 | 60 | ``` 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ``` 77 | 78 | 4. Update the cluster-connection section by replacing the message-load-balacing line with the following: 79 | 80 | ``` 81 | ON_DEMAND 82 | ``` 83 | 84 | This will prevent message starvation and enable message redistribution between nodes, as described [here](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/clustering#enabling_message_redistribution) 85 | 86 | 5. Startup both the master and slave brokers in separate consoles 87 | 88 | ``` 89 | ./brokers/master/bin/artemis run 90 | ./brokers/slave/bin/artemis run 91 | ``` 92 | 93 | 6. Using the legacy activemq client, run the following commands in two separate console windows: 94 | 95 | ``` 96 | java -jar activemq-all-5.11.0.redhat-630187.jar consumer --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' --user admin --password admin --destination queue://TEST 97 | 98 | java -jar activemq-all-5.11.0.redhat-630187.jar producer --sleep 100 --messageCount 1000 --user admin --password admin --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' —destination queue://TEST 99 | ``` 100 | 101 | 7. Kill the master broker, and observe failover of both consumer / producer processes to the slave broker 102 | 103 | 8. Startup the original master broker again. Kill the slave broker, and notice failover back to the original master. 104 | 105 | -------------------------------------------------------------------------------- /labs/60-clustering.md: -------------------------------------------------------------------------------- 1 | # Clustering AMQ7 brokers 2 | 3 | A-MQ 7 has the ability intelligently store & forward messages around a cluster of brokers in order to load-balance and prevent "starvation". In addition to that, however, a clustered setup is required in order to do any type of master/slave (whether shared store, or replicated). 4 | 5 | There are a few different options for configuring a clustered setup: 6 | 7 | * Multicast 8 | * JGroups 9 | * Static 10 | 11 | For the purposes of this lab, we will use the static option. You can refer to the product documentation [here](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/clustering) for more information on the other types. 12 | 13 | ## Prerequisites 14 | 15 | Download and install the A-MQ 7 broker package as described in [Lab 1](00-install-broker.md). 16 | 17 | ## Creating the brokers 18 | 19 | ``` 20 | $ $AMQ_HOME/bin/artemis create brokers/node1 --name node1 --user admin --password admin --allow-anonymous 21 | $ $AMQ_HOME/bin/artemis create brokers/node2 --name node2 --user admin --password admin --allow-anonymous --port-offset 1 22 | ``` 23 | 24 | _Note: We could have passed in some extra arguments to configure our cluster with some defaults, but instead we're going to manually configure the cluster via the `broker.xml` file so we can become familiar with the available options._ 25 | 26 | ## Editing the configuration 27 | 28 | __Node 1__ 29 | 30 | 1. Open up the `brokers/node1/etc/broker.xml` file in your favorite text editor. 31 | 32 | 2. Add the following elements anywhere under the `` element: 33 | 34 | ```xml 35 | 36 | tcp://localhost:61616 37 | tcp://localhost:61617 38 | 39 | 40 | admin 41 | admin 42 | 43 | 44 | 45 | node1-connector 46 | ON_DEMAND 47 | 48 | node2-connector 49 | 50 | 51 | 52 | ``` 53 | 54 | 3. Add the following elements anywhere under the `` element whose `match` attribute is equal to "#" (meaning it matches all addresses): 55 | 56 | ```xml 57 | 0 58 | ``` 59 | 60 | 4. Start the broker: 61 | 62 | ``` 63 | $ ./brokers/node1/bin/artemis run 64 | ``` 65 | 66 | __Node 2__ 67 | 68 | 1. Open up the `brokers/node2/etc/broker.xml` file in your favorite text editor. 69 | 70 | 2. Add the following elements anywhere under the `` element: 71 | 72 | ```xml 73 | 74 | tcp://localhost:61616 75 | tcp://localhost:61617 76 | 77 | 78 | admin 79 | admin 80 | 81 | 82 | 83 | node2-connector 84 | ON_DEMAND 85 | 86 | node1-connector 87 | 88 | 89 | 90 | ``` 91 | 92 | 3. Add the following elements anywhere under the `` element whose `match` attribute is equal to "#" (meaning it matches all addresses): 93 | 94 | ```xml 95 | 0 96 | ``` 97 | 98 | 4. Start the broker: 99 | 100 | ``` 101 | $ ./brokers/node2/bin/artemis run 102 | ``` 103 | 104 | ## Testing 105 | 106 | Open up two terminal windows and run the following commands: 107 | 108 | __Terminal 1__ 109 | 110 | ``` 111 | $ $AMQ_HOME/bin/artemis producer --verbose --user admin --password admin --sleep 1000 --message-count 100 --url 'tcp://localhost:61616' 112 | ``` 113 | 114 | __Terminal 2__ 115 | 116 | ``` 117 | $ $AMQ_HOME/bin/artemis consumer --verbose --user admin --password admin --message-count 100 --url 'tcp://localhost:61617' 118 | ``` 119 | 120 | You should see that the messages are produced to node1, but consumed from node2. 121 | -------------------------------------------------------------------------------- /labs/70-admin.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/70-admin.md -------------------------------------------------------------------------------- /labs/75-security.md: -------------------------------------------------------------------------------- 1 | # AMQ 7 Security 2 | 3 | One of the key differences with AMQ 7 is the addition of new permissions. AMQ 6 only had 3 permissions: 4 | 5 | 1. read 6 | 2. write 7 | 3. admin 8 | 9 | which are described in more detail [here](http://activemq.apache.org/security.html). 10 | 11 | AMQ 7 on the other hand extends to 10 permissions. They are: 12 | 13 | * createAddress 14 | * deleteAddress 15 | * createDurableQueue 16 | * deleteDurableQueue 17 | * createNonDurableQueue 18 | * deleteNonDurableQueue 19 | * send 20 | * consume 21 | * manage 22 | * browse 23 | 24 | With the additional 7 permissions, we have finer grain control over assigning roles to our users. For more information about these new roles and how they map to the legacy AMQ 6 roles, please refer to the AMQ 7 [docs](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_broker/security#ldap_authz). 25 | 26 | ## Security Labs 27 | 28 | ### Permissions / Roles Lab 1 29 | 30 | This lab demonstrates how to setup a read-only user on A-MQ i.e. the user can only consumer from a given queue. 31 | 32 | 1. Create a new broker by executing the following command: 33 | 34 | ``` 35 | ./bin/artemis create 36 | ``` 37 | 38 | Name the broker "securitybroker" and give it an admin user with the credentials admin/admin. 39 | 40 | 2. `cd` to `brokers/securitybroker/bin` 41 | 3. Execute `./artemis user add --user read-only-user --password Abcd1234 --role read-only` to create a read-only user 42 | 4. `cd` to `brokers/securitybroker/etc` and open the broker.xml file. 43 | 5. Under the security-settings section, add the following text: 44 | 45 | ``` 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ``` 60 | Notice we have a specific match for any queue starting with "test.*". Also notice that we have assigned the "read-only" role to ensure that our read-only user can only consume from our test.* queue. 61 | 62 | 5. Save the broker.xml file 63 | 64 | 6. Start up our new broker using the following command: `./brokers/securitybroker/bin/artemis run` 65 | 66 | 7. Try out our new "read only" role / user by typing the following command in a separate command windo: 67 | 68 | ``` 69 | java -jar activemq-all-5.11.0.redhat-630187.jar producer --sleep 100 --messageCount 1000 --user read-only-user --password Abcd1234 --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' --destination queue://test.readonly.queue 70 | ``` 71 | 72 | Notice that this command fails because our read-only-user cannot create a durable queue. This means our user is working correctly. 73 | 74 | 8. Change the command and execute the following instead to use the admin user, which coincidently has admin permissions to create and write to queues: 75 | 76 | ``` 77 | java -jar activemq-all-5.11.0.redhat-630187.jar producer --sleep 100 --messageCount 1000 --user admin --password admin --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' --destination queue://test.readonly.queue 78 | ``` 79 | 80 | 9. Now lets try consuming from the test.readonly.queue using the read-only-user credentials: 81 | 82 | ``` 83 | java -jar activemq-all-5.11.0.redhat-630187.jar consumer --sleep 100 --messageCount 1000 --user read-only-user --password Abcd1234 --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' --destination queue://test.readonly.queue 84 | ``` 85 | 86 | If all goes well, the client should connect and start consuming messages from our queue. 87 | 88 | 10. For the sake of testing, try the same to write messages to the queue. Again, this should fail but with a different permission error: 89 | 90 | ``` 91 | java -jar activemq-all-5.11.0.redhat-630187.jar producer --sleep 100 --messageCount 1000 --user read-only-user --password Abcd1234 --brokerUrl 'failover:(tcp://localhost:61616,tcp://localhost:61617)' --destination queue://test.readonly.queue 92 | ``` 93 | ### SSL 94 | 95 | This lab demonstrates generating keys and truststores to use for SSL with the broker. 96 | 97 | 1. Ensure openssl is installed 98 | 99 | ``` 100 | sudo yum install openssl 101 | ``` 102 | 103 | 2. Use openssl to generate the pem and p12 files. Other file formats can be used by the pem and p12 are compatiable for usage with both the Artemis brokers and then Interconnect Routers 104 | 105 | ``` 106 | openssl req -newkey rsa:2048 -nodes -keyout keyout.pem -x509 -days 65000 -out certificate.pem 107 | openssl x509 -text -noout -in certificate.pem 108 | openssl pkcs12 -inkey keyout.pem -in certificate.pem -export -out certificate.p12 109 | openssl pkcs12 -in certificate.p12 -noout -info 110 | ``` 111 | Notice this results in the following files 112 | ``` 113 | keyout.pem 114 | certificate.pem 115 | certificate.p12 116 | ``` 117 | 118 | 3. Configure SSL usage on the connectors and acceptors in the broker.xml 119 | 120 | ``` 121 | 122 | tcp://localhost:61616?sslEnabled=true;keyStorePath=certificate.p12;keyStorePassword=password;enabledProtocols=TLSv1,TLSv1.1,TLSv1.2;trustStorePath=certificate.p12; 123 | trustStorePassword=password 124 | 125 | 126 | tcp://localhost:61616?sslEnabled=true;keyStorePath=certificate.p12;keyStorePassword=password;enabledProtocols=TLSv1,TLSv1.1,TLSv1.2;trustStorePath=certificate.p12; 127 | trustStorePassword=password 128 | 129 | ``` 130 | 131 | 4. If you have multiple brokers configure those as well to ensure any clustering between the brokers will be able to communicate. 132 | 133 | 5. Start up the brokers, notice that the Cluster Bridge connections should still occur, but this time over SSL 134 | 135 | 6. Configure your client to use ssl, using a URL similar to the following 136 | 137 | ``` 138 | amqps://localhost:5672?transport.verifyHost=false&transport.storeType=PKCS12&transport.trustStoreLocation=/home/example/broker-secure/certificate.p12&transport.trustStorePassword=password 139 | ``` 140 | 141 | 7. Start up your client and see it connect with SSL and consume or produce 142 | -------------------------------------------------------------------------------- /labs/80-install-qdr.md: -------------------------------------------------------------------------------- 1 | # Installing and Configuring AMQ7 Interconnect Router 2 | 3 | The AMQ7 Interconnect Router components are written in native code (C++) and are supported on RHEL. In this lab, we'll take a look at two ways to bootstrap Interconnect Router for the purposes of demonstrating routing and broker to router connectivity. If you're looking to do an installation of Interconnect Router on your machines (ie, not just for following this lab), then the official documentation is quite good. [Check it out at access.redhat.com](https://access.redhat.com/documentation/en-us/red_hat_jboss_amq/7.0/html/using_amq_interconnect/installation) for doing a proper installation. 4 | 5 | 6 | ### Option 1 Install into a fresh copy of RHEL 7 7 | 8 | Option one requires you to have a RHEL host already provisioned. Either you can use one you already have, or for the purposes of this lab you can install a developer copy. If you go to [http://developers.redhat.com](http://developers.redhat.com), you'll notice lots of helpful tools for developers including e-books, cheatsheets, and community software. Go to the [Red Hat Enterprise Linux](https://developers.redhat.com/products/rhel/overview/) landing page and click "Download" to get yourself a free, developers edition of RHEL. From there you can install it as a *.iso (ie, so you can import it into virtualbox or something) 9 | 10 | If you're using the developers.redhat.com developer's copy of RHEL, you should automatically have a subscription to the right repos/channels to download and install Interconnect Router. 11 | 12 | You should be able to: 13 | 14 | ```bash 15 | sudo yum install qpid-proton-c python-qpid-proton 16 | sudo yum install qpid-dispatch-router qpid-dispatch-tools 17 | ``` 18 | 19 | If you've got your own RHEL 7 instance or you cannot install based on the above commands, we'll try to manually install. The binaries can be given out during in-person workshops. 20 | 21 | Once you've got RHEL set up, you can then install the Interconnect Router. First [Download a RHEL7 build of the Interconnect Router]() onto your RHEL machine (again, these binaries would be given out in person) 22 | 23 | 24 | Known to work on base RHEL7.x/Centos7.x distros: 25 | 26 | ```bash 27 | # Enable EPEL 28 | sudo rpm -i https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 29 | 30 | # Yum update 31 | sudo yum -y update 32 | 33 | # Install preprequisites 34 | sudo yum -y install qpid-proton-c-devel python-qpid-proton 35 | 36 | # Install Official release of router 37 | sudo rpm -Uvh libwebsockets-2.1.0-3.el7.x86_64.rpm 38 | sudo rpm -Uvh qpid-dispatch-router-0.8.0-9.el7.x86_64.rpm 39 | ``` 40 | 41 | ### Option 2 Using Docker 42 | 43 | With option 2, you can choose to use Docker and grab docker images. Note you'll need some kind of Linux machine (or VM) if your Host machine isn't Linux. This could be Docker for Mac/Windows, Minikube, or the Red Hat CDK 3.0. In any event, setting up Linux for Docker usage is beyond the scope of this installation documentation. Also, when doing any kind of port forwarding between the docker guest VM and your local workstation host, it's up to you to figure out how to open up the ports if you're trying to communicate locally with it. 44 | 45 | To get the docker image that contains the AMQ7 Interconnect Router: 46 | 47 | ```bash 48 | docker pull ceposta/qdr:latest 49 | ``` 50 | 51 | You can run the image like this: 52 | 53 | ```bash 54 | docker run -itd --name qdr ceposta/qdr:latest 55 | ``` 56 | 57 | In the next labs, we'll see how to attach configuration to the router. Default configuration is in `/etc/qpid-dispatch/qdrouterd.conf` 58 | 59 | -------------------------------------------------------------------------------- /labs/90-broker-to-router.md: -------------------------------------------------------------------------------- 1 | # Connecting the Interconnect Router to an AMQ7 Broker 2 | 3 | In this lab we'll take a look at configuring the Interconnect Router to route messages to and from an AMQ7 broker. Clients can talk directly to the router and think they're talking to a broker. 4 | 5 | In this lab, we'll use the Docker images from the [installing interconnect router](./80-install-qdr.md) lab. You can use the same configuration files that we'll use here in your full version of RHEL/CentOS if you've installed Interconnect Router there. The broker we'll use comes from the earlier labs; it will be running locally on your laptop. Remember, you'll need to configure port forwarding between your docker guest VM and your developer host machine. 6 | 7 | First thing we'll do is look at and modify the configuration where needed. If you look in the lab files [for the Interconnect Router configurations](./qdr/conf), you'll see a configuration file named `router-to-broker.conf` that looks like this: 8 | 9 | 10 | ```xml 11 | router { 12 | mode: standalone 13 | id: routerToBroker 14 | workerThreads: 4 15 | } 16 | 17 | listener { 18 | role: normal 19 | host: 0.0.0.0 20 | port: 5672 21 | linkCapacity: 1000 22 | } 23 | 24 | log { 25 | module: DEFAULT 26 | enable: trace+ 27 | timestamp: true 28 | } 29 | 30 | address { 31 | prefix: foo 32 | waypoint: yes 33 | } 34 | 35 | autoLink { 36 | addr: foo 37 | dir: in 38 | connection: myfirstbrokerConnector 39 | } 40 | 41 | autoLink { 42 | addr: foo 43 | dir: out 44 | connection: myfirstbrokerConnector 45 | } 46 | 47 | connector { 48 | host: 10.0.1.35 49 | name: myfirstbrokerConnector 50 | port: 61616 51 | role: route-container 52 | allowRedirect: no 53 | } 54 | 55 | 56 | ``` 57 | 58 | In this configuration, we're setting up a `listener` which listens for incoming connections to the router; for example, an AMQP client could connect directly to this listener (in this case, we're listening on port `5672` which is the default AMQP port). Also locate the `connector` section of the configuration. This describes how we'll connect to the AMQ7 broker. You'll want to change the host/port config to match that of your broker. For example, if you're running the broker on your local machine and the router in a docker container locally on a guest OS, you'd want to use your host IP for the broker's `connector.host` field. 59 | 60 | Let's make sure our broker from Lab 1, `myfirstbroker` is up and running: 61 | 62 | ```bash 63 | __ __ ____ ____ _ 64 | /\ | \/ |/ __ \ | _ \ | | 65 | / \ | \ / | | | | | |_) |_ __ ___ | | _____ _ __ 66 | / /\ \ | |\/| | | | | | _ <| '__/ _ \| |/ / _ \ '__| 67 | / ____ \| | | | |__| | | |_) | | | (_) | < __/ | 68 | /_/ \_\_| |_|\___\_\ |____/|_| \___/|_|\_\___|_| 69 | 70 | Red Hat JBoss AMQ 7.0.0.redhat-1 71 | 72 | 73 | 09:42:46,451 INFO [org.apache.activemq.artemis.integration.bootstrap] AMQ101000: Starting ActiveMQ Artemis Server 74 | 09:42:46,467 INFO [org.apache.activemq.artemis.core.server] AMQ221000: live Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=./data/journal,bindingsDirectory=./data/bindings,largeMessagesDirectory=./data/large-messages,pagingDirectory=./data/paging) 75 | 09:42:46,512 INFO [org.apache.activemq.artemis.core.server] AMQ221013: Using NIO Journal 76 | 09:42:46,611 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE 77 | 09:42:46,612 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-amqp-protocol]. Adding protocol support for: AMQP 78 | 09:42:46,612 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-hornetq-protocol]. Adding protocol support for: HORNETQ 79 | 09:42:46,612 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-mqtt-protocol]. Adding protocol support for: MQTT 80 | 09:42:46,613 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-openwire-protocol]. Adding protocol support for: OPENWIRE 81 | 09:42:46,613 INFO [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-stomp-protocol]. Adding protocol support for: STOMP 82 | 09:42:46,658 INFO [org.apache.activemq.artemis.core.server] AMQ221034: Waiting indefinitely to obtain live lock 83 | 09:42:46,658 INFO [org.apache.activemq.artemis.core.server] AMQ221035: Live Server Obtained live lock 84 | 09:42:47,152 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue exampleQueue 85 | 09:42:47,153 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue foo 86 | 09:42:47,153 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue DLQ 87 | 09:42:47,154 INFO [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue ExpiryQueue 88 | 09:42:47,858 INFO [org.apache.activemq.artemis.core.server] AMQ221020: Started NIO Acceptor at 0.0.0.0:61616 for protocols [CORE,MQTT,AMQP,STOMP,HORNETQ,OPENWIRE] 89 | 09:42:47,860 INFO [org.apache.activemq.artemis.core.server] AMQ221007: Server is now live 90 | 09:42:47,860 INFO [org.apache.activemq.artemis.core.server] AMQ221001: Apache ActiveMQ Artemis Message Broker version 2.0.0.amq-700005-redhat-1 [0.0.0.0, nodeID=ae7bf278-35c4-11e7-97d9-0a0027000001] 91 | INFO | main | Initialized artemis-plugin plugin 92 | INFO | main | Initialized dispatch-hawtio-console plugin 93 | 09:42:50,441 INFO [org.apache.activemq.artemis] AMQ241001: HTTP Server started at http://localhost:8161 94 | 09:42:50,441 INFO [org.apache.activemq.artemis] AMQ241002: Artemis Jolokia REST API available at http://localhost:8161/jolokia 95 | ``` 96 | 97 | Now let's try running the Interconnect Router with the above configuration (ie, change the `connector` host IP and port to match your settings): 98 | 99 | ```bash 100 | docker run -it --rm --name qdr -p 5672:5672 -v $(pwd)/qdr/conf/router-to-broker.conf:/etc/qpid-dispatch/qdrouterd.conf ceposta/qdr 101 | ``` 102 | 103 | Note how we map the configuration file into the docker container. When we run this, we should see output from the Interconnect Router similar to this: 104 | 105 | ```bash 106 | Thu May 25 09:46:19 2017 SERVER (trace) Connecting to 10.0.1.35:61616 107 | Thu May 25 09:46:19 2017 SERVER (trace) [1]: -> SASL 108 | Thu May 25 09:46:19 2017 SERVER (trace) [1]: <- SASL 109 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 <- @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:PLAIN, :ANONYMOUS]] 110 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 -> @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@0993bdacc124"] 111 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 <- @sasl-outcome(68) [code=0] 112 | Thu May 25 09:46:19 2017 SERVER (trace) [1]: <- AMQP 113 | Thu May 25 09:46:19 2017 SERVER (trace) [1]: -> AMQP 114 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 -> @open(16) [container-id="routerToBroker", hostname="10.0.1.35", max-frame-size=16384, channel-max=32767, idle-time-out=8000, offered-capabilities=:"ANONYMOUS-RELAY", properties={:product="qpid-dispatch-router", :version="0.8.0"}] 115 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 <- @open(16) [container-id="0.0.0.0", max-frame-size=4294967295, channel-max=65535, idle-time-out=30000, offered-capabilities=@PN_SYMBOL[:"sole-connection-for-container", :"DELAYED_DELIVERY", :"SHARED-SUBS", :"ANONYMOUS-RELAY"], properties={:product="apache-activemq-artemis", :version="2.0.0.amq-700005-redhat-1"}] 116 | Thu May 25 09:46:19 2017 ROUTER_CORE (trace) Core action 'connection_opened' 117 | Thu May 25 09:46:19 2017 ROUTER_CORE (info) Auto Link Activated 'autoLink/0' on connection myfirstbrokerConnector 118 | Thu May 25 09:46:19 2017 ROUTER_CORE (info) Auto Link Activated 'autoLink/1' on connection myfirstbrokerConnector 119 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 -> @begin(17) [next-outgoing-id=0, incoming-window=2147483647, outgoing-window=2147483647] 120 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:1 -> @begin(17) [next-outgoing-id=0, incoming-window=2147483647, outgoing-window=2147483647] 121 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 -> @attach(18) [name="qdlink.nxYIQdO8Jvut7LX", handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0, source=@source(40) [address="foo", durable=0, expiry-policy=:"link-detach", timeout=0, dynamic=false], target=@target(41) [durable=0, timeout=0, dynamic=false], initial-delivery-count=0, max-message-size=0] 122 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:1 -> @attach(18) [name="qdlink.NqqnFJ7_SOW_EWu", handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0, source=@source(40) [durable=0, timeout=0, dynamic=false], target=@target(41) [address="foo", durable=0, expiry-policy=:"link-detach", timeout=0, dynamic=false], initial-delivery-count=0, max-message-size=0] 123 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 <- @begin(17) [remote-channel=0, next-outgoing-id=1, incoming-window=2147483647, outgoing-window=2147483647, handle-max=65535] 124 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:1 <- @begin(17) [remote-channel=1, next-outgoing-id=1, incoming-window=2147483647, outgoing-window=2147483647, handle-max=65535] 125 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:0 <- @attach(18) [name="qdlink.nxYIQdO8Jvut7LX", handle=0, role=false, snd-settle-mode=2, rcv-settle-mode=0, source=@source(40) [address="foo", durable=0, expiry-policy=:"link-detach"], target=@target(41) [], incomplete-unsettled=false, initial-delivery-count=0] 126 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:1 <- @attach(18) [name="qdlink.NqqnFJ7_SOW_EWu", handle=0, role=true, snd-settle-mode=2, rcv-settle-mode=0, source=@source(40) [], target=@target(41) [address="foo", durable=0, expiry-policy=:"link-detach"]] 127 | Thu May 25 09:46:19 2017 SERVER (trace) [1]:1 <- @flow(19) [next-incoming-id=0, incoming-window=2147483647, next-outgoing-id=1, outgoing-window=2147483647, handle=0, delivery-count=0, link-credit=1000] 128 | Thu May 25 09:46:19 2017 ROUTER_CORE (trace) Core action 'link_second_attach' 129 | Thu May 25 09:46:19 2017 ROUTER_CORE (trace) Core action 'link_second_attach' 130 | Thu May 25 09:46:19 2017 ROUTER_CORE (trace) Core action 'link_flow' 131 | ``` 132 | 133 | Fire up the web console for the broker at [http://localhost:8161/hawtio](http://localhost:8161/hawtio) and try to find the `address.hellowrold` destination. 134 | 135 | ![](images/broker-to-router/helloworldaddress.png) 136 | 137 | As we send messages in to the router, you should watch the `foo` queue and see its message count increase. 138 | 139 | ### Sending messages into the Router 140 | 141 | To send messages into the router, we'll go [back to the JMS AMQP client in the Clients Lab](./20-clients.md) and configure it to send messages to the `5672` port (which is the default AMQP port: 142 | 143 | Our `jndi.properties` file should look like this, with the `connectionfactory.myFactoryLookup` property set to `5672` 144 | 145 | ``` 146 | # Set the InitialContextFactory class to use 147 | java.naming.factory.initial = org.apache.qpid.jms.jndi.JmsInitialContextFactory 148 | 149 | # Define the required ConnectionFactory instances 150 | # connectionfactory. = 151 | connectionfactory.myFactoryLookup = amqp://localhost:5672 152 | 153 | # Configure the necessary Queue and Topic objects 154 | # queue. = 155 | # topic. = 156 | queue.myQueueLookup = queue 157 | topic.myTopicLookup = topic 158 | ``` 159 | 160 | The last thing we need to do is port-forward the guest OS to our host OS. If you recall, when we started the docker container for our router, we passed in the `-p 5672:5672` flag which exposes the `5672` port on the docker container to the host. Except, since the docker daemon is running in our guest VM, it cannot be seen on the host. 161 | 162 | If using minikube, do this achieve the port forwarding: 163 | 164 | ```bash 165 | minikube ssh -- -vnNTL *:5672:$(minikube ip):5672 166 | ``` 167 | 168 | Now run your JMS client: 169 | 170 | ```bash 171 | java -cp "target/classes/:target/dependency/*" org.apache.qpid.jms.example.HelloWorld 172 | Hello world! 173 | ``` 174 | 175 | If we see the `Hello world!` response, it means our message went to the router, into the broker, and back out that way to the JMS consumer as we expected! -------------------------------------------------------------------------------- /labs/README.md: -------------------------------------------------------------------------------- 1 | # Red Hat JBoss AMQ 7 Labs 2 | 3 | These set of labs will help a new user learn how to install, configure and use JBoss AMQ 7. We'll cover topics like clustering, high availability, persistence, and the new Interconnect Router. 4 | 5 | ## Prerequisites 6 | 7 | To get started with these labs, you'll want to install (and have correctly configured) the following prerequisites: 8 | 9 | * JDK 8 ([OpenJDK](http://openjdk.java.net/install/) or [OracleJDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)) 10 | * [Apache Maven 3.3+](https://maven.apache.org/download.cgi) 11 | * Zip/Unzip utility 12 | * [Git Command Line](https://git-scm.com/downloads) 13 | 14 | ## Contributing to the labs 15 | 16 | We are always happy to accept contributions in the form of correcting errors, adding new labs, making certain points more clear, etc. Please open [Issues](https://github.com/RedHatWorkshops/amqv7-workshop/issues) on this GitHub repo identifying what things you'd like to contribute and then send [Pull Requests](https://github.com/RedHatWorkshops/amqv7-workshop/pulls)! 17 | 18 | The Lab guides are written in [Markdown](https://daringfireball.net/projects/markdown/syntax) and are organized/compiled with [Gitbook](https://www.gitbook.com). When you make changes, please also take the time to build/compile/preview the changes using gitbook. See below for instructions on how to build the source. 19 | 20 | ## Building the Gitbook 21 | We are using Gitbook to organize and build the lab guide. We highly recommend you [install the gitbook-cli](https://github.com/GitbookIO/gitbook-cli) tools to help you build and preview the labs in Gitbook format. If you have the `gitbook-cli` tools installed, you can navigate to this folder (ie, `amqv7-workshop/labs`) and run the following commands: 22 | 23 | 24 | $ gitbook install 25 | $ gitbook build . 26 | 27 | Then if you look in the `_book` folder, you should see the HTML files generated for this book. Open the `index.html` file from that folder to have your book. 28 | 29 | You can also set up live preview of the book by running this command: 30 | 31 | $ gitbook serve 32 | 33 | Then you should see something similar to this: 34 | 35 | ``` 36 | info: loading book configuration....OK 37 | info: load plugin gitbook-plugin-anchors ....OK 38 | info: load plugin gitbook-plugin-highlight ....OK 39 | info: load plugin gitbook-plugin-search ....OK 40 | info: load plugin gitbook-plugin-sharing ....OK 41 | info: load plugin gitbook-plugin-fontsettings ....OK 42 | info: load plugin gitbook-plugin-livereload ....OK 43 | info: >> 6 plugins loaded 44 | info: start generation with website generator 45 | info: clean website generator 46 | info: OK 47 | info: generation is finished 48 | 49 | Starting server ... 50 | Serving book on http://localhost:4000 51 | ``` 52 | 53 | Now navigate to [http://localhost:4000](http://localhost:4000) to see the live-updating Gitbook. If you make changes to the source they'll automatically be built and updated in the web page. 54 | 55 | 56 | Lastly, to build the Gitbook as a PDF file, run the following command (from the `./labs` folder): 57 | 58 | $ gitbook pdf . 59 | 60 | You should see a file named `book.pdf` in the `./labs` folder. 61 | 62 | 63 | ## Updating the https://redhatworkshops.github.io/ labs website 64 | 65 | To do this, first build the gitbook HTML source, then push to the `gh-pages` branch: 66 | 67 | rm -fr _book 68 | gitbook build . 69 | cd _book 70 | git init 71 | git commit --allow-empty -m 'initial commit' 72 | git checkout -b gh-pages 73 | git add . 74 | git commit -am 'updated docs' 75 | git push --force https://github.com/RedHatWorkshops/amqv7-workshop.git gh-pages 76 | 77 | All of this can be found in the `publish-labs.sh` script. 78 | -------------------------------------------------------------------------------- /labs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Installing the AMQ7 Broker](00-install-broker.md) 4 | * [Configuring AMQ 7](10-configure-broker.md) 5 | * [AMQ 7 Clients](20-clients.md) 6 | * [Producing and Consuming](30-produce-consume.md) 7 | * [Persistence / Master-Slave](40-master-slave.md) 8 | * [Persistence / Replication](50-replication.md) 9 | * [Simple Clustering](60-clustering.md) 10 | * [Administration](70-admin.md) 11 | * [Security](75-security.md) 12 | * [Installing Interconnect Router](80-install-qdr.md) 13 | * [Connect router to broker](90-broker-to-router.md) 14 | * [Brokerless routing](100-brokerless.md) 15 | -------------------------------------------------------------------------------- /labs/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "JBoss AMQ 7 Labs", 3 | "description": "A series of labs intended to go along with the AMQ 7 workshop to help users understand JBoss AMQ 7", 4 | "extension": "pdf", 5 | "github": "RedHatWorkshops/amqv7-workshop", 6 | "githubHost": "https://github.com/", 7 | "gitbook": ">=2.0.0", 8 | 9 | "links": { 10 | "home": "https://github.com/RedHatWorkshops/amqv7-workshop", 11 | "issues": "https://github.com/RedHatWorkshops/amqv7-workshopissues?milestone=none&state=closed" 12 | }, 13 | "plugins": [ 14 | "anchors" 15 | ], 16 | 17 | "pdf": { 18 | "toc": true, 19 | "fontSize": 12, 20 | "paperSize": "a4", 21 | "margin": { 22 | "right": 62, 23 | "left": 62, 24 | "top": 36, 25 | "bottom": 36 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /labs/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/.gitkeep -------------------------------------------------------------------------------- /labs/images/broker-to-router/helloworldaddress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/broker-to-router/helloworldaddress.png -------------------------------------------------------------------------------- /labs/images/client/download-jms-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/client/download-jms-client.png -------------------------------------------------------------------------------- /labs/images/client/download-node-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/client/download-node-client.png -------------------------------------------------------------------------------- /labs/images/configuration/startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/configuration/startup.png -------------------------------------------------------------------------------- /labs/images/install/downloadbroker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/install/downloadbroker.png -------------------------------------------------------------------------------- /labs/images/produce-consume/consume-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/produce-consume/consume-50.png -------------------------------------------------------------------------------- /labs/images/produce-consume/consumer-drain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/produce-consume/consumer-drain.png -------------------------------------------------------------------------------- /labs/images/produce-consume/dlq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/produce-consume/dlq.png -------------------------------------------------------------------------------- /labs/images/produce-consume/producer-message-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/labs/images/produce-consume/producer-message-count.png -------------------------------------------------------------------------------- /labs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AMQ7 Labs", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "docs:prepare": "gitbook install", 6 | "docs:watch": "npm run docs:prepare && gitbook serve" 7 | } 8 | } -------------------------------------------------------------------------------- /labs/publish-labs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rm -fr _book 3 | gitbook build . 4 | cd _book 5 | git init 6 | git commit --allow-empty -m 'initial commit' 7 | git checkout -b gh-pages 8 | git add . 9 | git commit -am 'updated docs' 10 | git push --force https://github.com/RedHatWorkshops/amqv7-workshop.git gh-pages 11 | -------------------------------------------------------------------------------- /labs/qdr/brokerless/receiver_router3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker run -e QPID_LOG_ENABLE=trace+ --link router3:router3 -t -i scholzj/qpid-cpp:latest qpid-receive -b router3:5672 --connection-options "{protocol: amqp1.0}" -a "'/myAddress'" -m 1 -f --print-headers yes -------------------------------------------------------------------------------- /labs/qdr/brokerless/router1.conf: -------------------------------------------------------------------------------- 1 | router { 2 | mode: interior 3 | id: Router1 4 | workerThreads: 4 5 | } 6 | 7 | listener { 8 | role: normal 9 | host: 0.0.0.0 10 | port: 5672 11 | linkCapacity: 1000 12 | } 13 | 14 | listener { 15 | role: inter-router 16 | host: 0.0.0.0 17 | port: 10001 18 | } 19 | 20 | listener { 21 | role: normal 22 | host: 0.0.0.0 23 | port: 2009 24 | linkCapacity: 1000 25 | } 26 | 27 | log { 28 | module: DEFAULT 29 | enable: trace+ 30 | timestamp: true 31 | } 32 | 33 | connector { 34 | role: inter-router 35 | host: router2 36 | port: 10002 37 | saslMechanisms: ANONYMOUS 38 | } 39 | 40 | connector { 41 | role: inter-router 42 | host: router3 43 | port: 10003 44 | saslMechanisms: ANONYMOUS 45 | } 46 | 47 | address { 48 | prefix: /myAddress 49 | distribution: closest 50 | } 51 | -------------------------------------------------------------------------------- /labs/qdr/brokerless/router2.conf: -------------------------------------------------------------------------------- 1 | router { 2 | mode: interior 3 | id: Router2 4 | workerThreads: 4 5 | } 6 | 7 | listener { 8 | role: inter-router 9 | host: 0.0.0.0 10 | port: 10002 11 | } 12 | 13 | log { 14 | module: DEFAULT 15 | enable: trace+ 16 | timestamp: true 17 | } 18 | 19 | connector { 20 | role: inter-router 21 | host: router3 22 | port: 10003 23 | saslMechanisms: ANONYMOUS 24 | } 25 | 26 | address { 27 | prefix: /myAddress 28 | distribution: closest 29 | } 30 | -------------------------------------------------------------------------------- /labs/qdr/brokerless/router3.conf: -------------------------------------------------------------------------------- 1 | router { 2 | mode: interior 3 | id: Router3 4 | workerThreads: 4 5 | } 6 | 7 | listener { 8 | role: normal 9 | host: 0.0.0.0 10 | port: 5672 11 | linkCapacity: 1000 12 | } 13 | 14 | listener { 15 | role: inter-router 16 | host: 0.0.0.0 17 | port: 10003 18 | } 19 | 20 | log { 21 | module: DEFAULT 22 | enable: trace+ 23 | timestamp: true 24 | } 25 | 26 | address { 27 | prefix: /myAddress 28 | distribution: closest 29 | } 30 | -------------------------------------------------------------------------------- /labs/qdr/brokerless/sender_router1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker run -e QPID_LOG_ENABLE=trace+ --link router1:router1 -t -i scholzj/qpid-cpp:latest qpid-send -b router1:5672 --connection-options "{protocol: amqp1.0}" -a "'/myAddress'" -m 1 -------------------------------------------------------------------------------- /labs/qdr/brokerless/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | docker run -itd --name router3 -v $(pwd)/router3.conf:/etc/qpid-dispatch/qdrouterd.conf ceposta/qdr 5 | docker run -itd --name router2 --link router3 -v $(pwd)/router2.conf:/etc/qpid-dispatch/qdrouterd.conf ceposta/qdr 6 | docker run -itd --name router1 --link router3 --link router2 -v $(pwd)/router1.conf:/etc/qpid-dispatch/qdrouterd.conf ceposta/qdr -------------------------------------------------------------------------------- /labs/qdr/brokerless/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | docker rm -f router1 router2 router3 -------------------------------------------------------------------------------- /labs/qdr/conf/router-to-broker.conf: -------------------------------------------------------------------------------- 1 | router { 2 | mode: standalone 3 | id: routerToBroker 4 | workerThreads: 4 5 | } 6 | 7 | listener { 8 | role: normal 9 | host: 0.0.0.0 10 | port: 5672 11 | linkCapacity: 1000 12 | } 13 | 14 | log { 15 | module: DEFAULT 16 | enable: trace+ 17 | timestamp: true 18 | } 19 | 20 | address { 21 | prefix: foo 22 | waypoint: yes 23 | } 24 | 25 | autoLink { 26 | addr: foo 27 | dir: in 28 | connection: myfirstbrokerConnector 29 | } 30 | 31 | autoLink { 32 | addr: foo 33 | dir: out 34 | connection: myfirstbrokerConnector 35 | } 36 | 37 | connector { 38 | host: 10.0.1.35 39 | name: myfirstbrokerConnector 40 | port: 61616 41 | role: route-container 42 | allowRedirect: no 43 | } 44 | -------------------------------------------------------------------------------- /slides/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/slides/.gitkeep -------------------------------------------------------------------------------- /slides/AMQ-Deepdive-Slides.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/slides/AMQ-Deepdive-Slides.pptx -------------------------------------------------------------------------------- /slides/IntroducingJBossAMQ7.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedHatWorkshops/amqv7-workshop/2d2fbc52d3f5d47387b02257ccb3b7085aa4e9f5/slides/IntroducingJBossAMQ7.pptx -------------------------------------------------------------------------------- /usecases/banking-service/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Banking Service Usecase 2 | -------------------------------------------------------------------------------- /usecases/call-center/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Call Center Service Usecase 2 | -------------------------------------------------------------------------------- /usecases/healthcare-institution/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Healthcare Institution Usecase 2 | -------------------------------------------------------------------------------- /usecases/online-retail/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Online Retail Service Usecase 2 | -------------------------------------------------------------------------------- /usecases/telecom-service-provider/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Telecom Service Provider Usecase 2 | -------------------------------------------------------------------------------- /usecases/transportation-ticket-service/README.md: -------------------------------------------------------------------------------- 1 | # JBoss A-MQ 7 Transportation Ticket Service Usecase 2 | --------------------------------------------------------------------------------