├── .DS_Store ├── .gitignore ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── README.md ├── helloworld ├── .springBeans ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── springframework │ │ └── amqp │ │ └── helloworld │ │ ├── BrokerConfigurationApplication.java │ │ ├── Consumer.java │ │ ├── HelloWorldConfiguration.java │ │ ├── Producer.java │ │ └── async │ │ ├── Consumer.java │ │ ├── ConsumerConfiguration.java │ │ ├── HelloWorldHandler.java │ │ ├── Producer.java │ │ └── ProducerConfiguration.java │ └── resources │ ├── log4j2.xml │ └── rabbitConfiguration.xml ├── log4j2 ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── springframework │ │ └── amqp │ │ └── samples │ │ └── log4j2 │ │ └── SpringBootAmqpAppenderApplication.java │ └── resources │ └── log4j2.xml ├── mvnw ├── mvnw.cmd ├── pom.xml ├── rabbitmq-tutorials └── README.md ├── spring-rabbit-confirms-returns ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── samples │ │ │ └── confirms │ │ │ └── SpringRabbitConfirmsReturnsApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── samples │ └── confirms │ └── SpringRabbitConfirmsReturnsApplicationTests.java ├── spring-rabbit-global-errorhandler ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── samples │ │ │ └── errorhandler │ │ │ └── Application.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── samples │ └── errorhandler │ └── ApplicationTests.java ├── spring-rabbit-json ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── samples │ │ │ └── json │ │ │ └── Application.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── samples │ └── json │ └── ApplicationTests.java ├── spring-rabbit-streams ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── springframework │ │ │ └── amqp │ │ │ └── samples │ │ │ └── streams │ │ │ └── SpringRabbitStreamsApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── org │ └── springframework │ └── amqp │ └── samples │ └── streams │ └── SpringRabbitStreamsApplicationTests.java └── stocks ├── .DS_Store ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── springframework │ │ └── amqp │ │ └── rabbit │ │ └── stocks │ │ ├── config │ │ ├── AbstractStockAppRabbitConfiguration.java │ │ ├── RoutingKey.java │ │ ├── client │ │ │ └── RabbitClientConfiguration.java │ │ └── server │ │ │ └── RabbitServerConfiguration.java │ │ ├── domain │ │ ├── Quote.java │ │ ├── Stock.java │ │ ├── StockExchange.java │ │ ├── TradeRequest.java │ │ └── TradeResponse.java │ │ ├── gateway │ │ ├── MarketDataGateway.java │ │ ├── RabbitMarketDataGateway.java │ │ ├── RabbitStockServiceGateway.java │ │ └── StockServiceGateway.java │ │ ├── handler │ │ ├── ClientHandler.java │ │ └── ServerHandler.java │ │ ├── service │ │ ├── CreditCheckService.java │ │ ├── ExecutionVenueService.java │ │ ├── TradingService.java │ │ └── stubs │ │ │ ├── CreditCheckServiceStub.java │ │ │ ├── ExecutionVenueServiceStub.java │ │ │ └── TradingServiceStub.java │ │ ├── ui │ │ ├── StockController.java │ │ └── StockPanel.java │ │ └── web │ │ └── QuoteController.java ├── resources │ ├── client-bootstrap-config.xml │ ├── client-handlers.xml │ ├── client-messaging.xml │ ├── client.properties │ ├── log4j2.xml │ ├── server-bootstrap-config.xml │ ├── server-handlers.xml │ ├── server-jmx.xml │ ├── server-messaging.xml │ ├── server-services.xml │ ├── servlet-config.xml │ └── static │ │ ├── css │ │ ├── colors.css │ │ ├── local.css │ │ └── main.css │ │ ├── images │ │ ├── ajax-loader.gif │ │ ├── delete.png │ │ ├── favicon.ico │ │ ├── footer-left.png │ │ ├── footer-right.png │ │ ├── footer-stretch.png │ │ ├── header-left.png │ │ ├── header-right.png │ │ ├── header-stretch.png │ │ ├── help.png │ │ ├── issues.gif │ │ ├── module-icon.png │ │ ├── powered-by-spring.png │ │ ├── primary-item-background.png │ │ ├── primary-menu-stretch.png │ │ ├── primary-wrapper-left.png │ │ ├── primary-wrapper-right.png │ │ ├── springsource_logo.png │ │ ├── table-header-background.png │ │ ├── table-header-bottom-background.png │ │ └── table-header-top-background.png │ │ └── js │ │ ├── jquery.min.js │ │ └── jquery.mustache.js └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp └── test ├── java └── org │ └── springframework │ └── amqp │ └── rabbit │ └── stocks │ ├── Client.java │ ├── Server.java │ └── web │ └── ServletConfigurationTests.java └── resources └── test.yaml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | .classpath 4 | .project 5 | .settings 6 | .springBeans 7 | .ant-targets-build.xml 8 | src/ant/.ant-targets-upload-dist.xml 9 | *.swp 10 | */src/main/java/META-INF 11 | */src/main/webapp/META-INF 12 | erl_crash.dump 13 | nohup.out 14 | jredis.log 15 | .idea 16 | *.iml 17 | *.ipr 18 | *.iws 19 | .sts4-cache 20 | .factorypath 21 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with 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, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project hosts some samples that complement [Spring AMQP](https://github.com/SpringSource/spring-amqp), showing you how to get started with Spring and AMQP. 2 | 3 | # Build Instructions # 4 | 5 | Install the [RabbitMQ](https://www.rabbitmq.com) broker first (version 6 | 2.3.1 or better). Then clone from GIT and then use Maven (2.1.*): 7 | 8 | $ git clone ... 9 | $ mvn install 10 | 11 | SpringSource ToolSuite users (or Eclipse users with the latest 12 | m2eclipse plugin) can import the projects as existing Maven projects. 13 | 14 | The basic HelloWorld sample has two versions (with synchronous and 15 | asynchronous consumers). Both have two Java classes called `Producer` 16 | and `Consumer` with main methods to launch. Run the producer first 17 | and ensure that the broker is already running. 18 | 19 | The Stocks sample has a UI that can be launched as a Java main, and a 20 | daemon server process with the same properties. You can run them from 21 | an IDE easily. Run the `Server` and then the `Client` and you should 22 | see a swing client pop up and stock tickers appearing. To run from 23 | the command line you can use the Maven exec plugin: 24 | 25 | $ mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass=org.springframework.amqp.rabbit.stocks.Server & 26 | $ mvn exec:java -Dexec.classpathScope=test -Dexec.mainClass=org.springframework.amqp.rabbit.stocks.Client 27 | 28 | In the example above we backgrounded the server process, or you could 29 | run it in a different window to make things clearer in the console 30 | logs. 31 | 32 | ## Web UI 33 | 34 | The Stocks sample is also a web application. You should be able to run it in your IDE, e.g. if you imported the project into STS (or Eclipse with Maven support) you can drag it onto a server, or use `Run As...->On Server`. From the command line you can use 35 | 36 | $ mvn jetty:run 37 | 38 | The web UI is designed like the swing client - it has a ticker table 39 | that updates every second (if there is any new data), and an order 40 | entry form. The `QuoteController` manages the interaction between the 41 | browser and the application and between the application and the AMQP 42 | broker. 43 | 44 | ## RabbitMQ Tutorials 45 | 46 | Spring Boot versions of the [6 standard RabbitMQ tutorials](https://www.rabbitmq.com/getstarted.html) are provided in `rabbitmq-tutorials`. 47 | 48 | ## Spring Boot Applications 49 | 50 | Several Spring Boot applications are also provided, with names `spring-rabbit-...`. 51 | Explore their individual READMEs for more information. 52 | 53 | # Contributing to Spring AMQP Samples 54 | 55 | Here are some ways for you to get involved in the community: 56 | 57 | * Get involved with the Spring community on the Spring Community Forums. Please help out on the [forum](https://forum.spring.io/) by responding to questions and joining the debate. 58 | * Create [JIRA](https://jira.springsource.org/browse/AMQP) tickets for bugs and new features and comment and vote on the ones that you are interested in. 59 | * Github is for social coding: if you want to write code, we encourage contributions through pull requests from [forks of this repository](https://help.github.com/forking/). If you want to contribute code this way, please reference a JIRA ticket as well covering the specific issue you are addressing. 60 | * Watch for upcoming articles on Spring by [subscribing](https://www.springsource.org/node/feed) to springframework.org 61 | 62 | Refer to the spring-amqp [Contributor's Guidelines](https://github.com/spring-projects/spring-amqp/blob/master/CONTRIBUTING.adoc) for complete information about the necessary steps. 63 | 64 | ## Code Conventions and Housekeeping 65 | None of these is essential for a pull request, but they will all help. They can also be added after the original pull request but before a merge. 66 | 67 | * Use the Spring Framework code format conventions (import `eclipse-code-formatter.xml` from the root of the project if you are using Eclipse). 68 | * Make sure all new .java files to have a simple Javadoc class comment with at least an @author tag identifying you, and preferably at least a paragraph on what the class is for. 69 | * Add the ASF license header comment to all new .java files (copy from existing files in the project) 70 | * Add yourself as an @author to the .java files that you modify substantially (more than cosmetic changes). 71 | * Add some Javadocs and, if you change the namespace, some XSD doc elements (Spring AMQP is not stellar in this area yet, but it will have to come up to scratch one day, so you will be helping a lot). 72 | * A few unit tests would help a lot as well - someone has to do it. 73 | * If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project). 74 | -------------------------------------------------------------------------------- /helloworld/.springBeans: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | src/main/resources/rabbitConfiguration.xml 11 | 12 | 13 | 14 | 15 | true 16 | false 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /helloworld/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | org.springframework.samples.spring 7 | spring-rabbit-helloworld 8 | 3.2.0 9 | jar 10 | Spring AMQP Hello World 11 | https://www.spring.io 12 | 13 | 16 | 17 | 18 | true 19 | ${project.version} 20 | UTF-8 21 | 17 22 | false 23 | 24 | 25 | 26 | 27 | org.springframework.amqp 28 | spring-rabbit 29 | ${spring-amqp.version} 30 | 31 | 32 | 33 | org.apache.logging.log4j 34 | log4j-jcl 35 | 2.12.0 36 | runtime 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | maven-assembly-plugin 46 | false 47 | 48 | 49 | project 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.apache.maven.plugins 58 | maven-compiler-plugin 59 | 3.8.1 60 | 61 | 17 62 | 17 63 | 64 | 65 | 66 | org.apache.maven.plugins 67 | maven-surefire-plugin 68 | 2.22.2 69 | 70 | 71 | 72 | **/*Tests.java 73 | 74 | 75 | **/Abstract*.java 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/BrokerConfigurationApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld; 2 | 3 | import org.springframework.amqp.core.AmqpAdmin; 4 | import org.springframework.amqp.core.Queue; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.support.ClassPathXmlApplicationContext; 7 | 8 | public class BrokerConfigurationApplication { 9 | 10 | /** 11 | * An example application that only configures the AMQP broker 12 | */ 13 | public static void main(String[] args) throws Exception { 14 | ApplicationContext context = new ClassPathXmlApplicationContext("rabbitConfiguration.xml"); 15 | AmqpAdmin amqpAdmin = context.getBean(AmqpAdmin.class); 16 | Queue helloWorldQueue = new Queue("hello.world.queue"); 17 | 18 | amqpAdmin.declareQueue(helloWorldQueue); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/Consumer.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld; 2 | 3 | import org.springframework.amqp.core.AmqpTemplate; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 6 | 7 | public class Consumer { 8 | 9 | public static void main(String[] args) { 10 | ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class); 11 | AmqpTemplate amqpTemplate = context.getBean(AmqpTemplate.class); 12 | System.out.println("Received: " + amqpTemplate.receiveAndConvert()); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/HelloWorldConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld; 2 | 3 | import org.springframework.amqp.core.AmqpAdmin; 4 | import org.springframework.amqp.core.Queue; 5 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 6 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 7 | import org.springframework.amqp.rabbit.core.RabbitAdmin; 8 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | @Configuration 13 | public class HelloWorldConfiguration { 14 | 15 | protected final String helloWorldQueueName = "hello.world.queue"; 16 | 17 | @Bean 18 | public ConnectionFactory connectionFactory() { 19 | CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost"); 20 | connectionFactory.setUsername("guest"); 21 | connectionFactory.setPassword("guest"); 22 | return connectionFactory; 23 | } 24 | 25 | @Bean 26 | public AmqpAdmin amqpAdmin() { 27 | return new RabbitAdmin(connectionFactory()); 28 | } 29 | 30 | @Bean 31 | public RabbitTemplate rabbitTemplate() { 32 | RabbitTemplate template = new RabbitTemplate(connectionFactory()); 33 | //The routing key is set to the name of the queue by the broker for the default exchange. 34 | template.setRoutingKey(this.helloWorldQueueName); 35 | //Where we will synchronously receive messages from 36 | template.setDefaultReceiveQueue(this.helloWorldQueueName); 37 | return template; 38 | } 39 | 40 | @Bean 41 | // Every queue is bound to the default direct exchange 42 | public Queue helloWorldQueue() { 43 | return new Queue(this.helloWorldQueueName); 44 | } 45 | 46 | /* 47 | @Bean 48 | public Binding binding() { 49 | return declare(new Binding(helloWorldQueue(), defaultDirectExchange())); 50 | }*/ 51 | 52 | /* 53 | @Bean 54 | public TopicExchange helloExchange() { 55 | return declare(new TopicExchange("hello.world.exchange")); 56 | }*/ 57 | 58 | /* 59 | public Queue declareUniqueQueue(String namePrefix) { 60 | Queue queue = new Queue(namePrefix + "-" + UUID.randomUUID()); 61 | rabbitAdminTemplate().declareQueue(queue); 62 | return queue; 63 | } 64 | 65 | // if the default exchange isn't configured to your liking.... 66 | @Bean Binding declareP2PBinding(Queue queue, DirectExchange exchange) { 67 | return declare(new Binding(queue, exchange, queue.getName())); 68 | } 69 | 70 | @Bean Binding declarePubSubBinding(String queuePrefix, FanoutExchange exchange) { 71 | return declare(new Binding(declareUniqueQueue(queuePrefix), exchange)); 72 | } 73 | 74 | @Bean Binding declarePubSubBinding(UniqueQueue uniqueQueue, TopicExchange exchange) { 75 | return declare(new Binding(uniqueQueue, exchange)); 76 | } 77 | 78 | @Bean Binding declarePubSubBinding(String queuePrefix, TopicExchange exchange, String routingKey) { 79 | return declare(new Binding(declareUniqueQueue(queuePrefix), exchange, routingKey)); 80 | }*/ 81 | 82 | } 83 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/Producer.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld; 2 | 3 | import org.springframework.amqp.core.AmqpTemplate; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 6 | 7 | public class Producer { 8 | 9 | public static void main(String[] args) { 10 | ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class); 11 | AmqpTemplate amqpTemplate = context.getBean(AmqpTemplate.class); 12 | amqpTemplate.convertAndSend("Hello World"); 13 | System.out.println("Sent: Hello World"); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/async/Consumer.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld.async; 2 | 3 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 | 5 | public class Consumer { 6 | 7 | public static void main(String[] args) { 8 | new AnnotationConfigApplicationContext(ConsumerConfiguration.class); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/async/ConsumerConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld.async; 2 | 3 | import org.springframework.amqp.helloworld.HelloWorldConfiguration; 4 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 5 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class ConsumerConfiguration extends HelloWorldConfiguration { 11 | 12 | @Bean 13 | public SimpleMessageListenerContainer listenerContainer() { 14 | SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); 15 | container.setConnectionFactory(connectionFactory()); 16 | container.setQueueNames(this.helloWorldQueueName); 17 | container.setMessageListener(new MessageListenerAdapter(new HelloWorldHandler())); 18 | return container; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/async/HelloWorldHandler.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld.async; 2 | 3 | public class HelloWorldHandler { 4 | 5 | public void handleMessage(String text) { 6 | System.out.println("Received: " + text); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/async/Producer.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld.async; 2 | 3 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 | 5 | public class Producer { 6 | 7 | public static void main(String[] args) throws Exception { 8 | new AnnotationConfigApplicationContext(ProducerConfiguration.class); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /helloworld/src/main/java/org/springframework/amqp/helloworld/async/ProducerConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.helloworld.async; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 6 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 7 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.config.BeanPostProcessor; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.scheduling.annotation.Scheduled; 13 | import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor; 14 | 15 | @Configuration 16 | public class ProducerConfiguration { 17 | 18 | protected final String helloWorldQueueName = "hello.world.queue"; 19 | 20 | @Bean 21 | public RabbitTemplate rabbitTemplate() { 22 | RabbitTemplate template = new RabbitTemplate(connectionFactory()); 23 | template.setRoutingKey(this.helloWorldQueueName); 24 | return template; 25 | } 26 | 27 | @Bean 28 | public ConnectionFactory connectionFactory() { 29 | CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost"); 30 | connectionFactory.setUsername("guest"); 31 | connectionFactory.setPassword("guest"); 32 | return connectionFactory; 33 | } 34 | 35 | @Bean 36 | public ScheduledProducer scheduledProducer() { 37 | return new ScheduledProducer(); 38 | } 39 | 40 | @Bean 41 | public BeanPostProcessor postProcessor() { 42 | return new ScheduledAnnotationBeanPostProcessor(); 43 | } 44 | 45 | 46 | static class ScheduledProducer { 47 | 48 | @Autowired 49 | private volatile RabbitTemplate rabbitTemplate; 50 | 51 | private final AtomicInteger counter = new AtomicInteger(); 52 | 53 | @Scheduled(fixedRate = 3000) 54 | public void sendMessage() { 55 | rabbitTemplate.convertAndSend("Hello World " + counter.incrementAndGet()); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /helloworld/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /helloworld/src/main/resources/rabbitConfiguration.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /log4j2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.amqp.samples 7 | log4j2 8 | 3.2.0 9 | jar 10 | 11 | log4j2 12 | Spring Boot with Spring AMQP Log4J2 Appender 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 3.4.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 17 24 | ${project.version} 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-amqp 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-logging 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-log4j2 42 | 43 | 44 | 45 | org.springframework 46 | spring-jcl 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-test 52 | test 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | 65 | 66 | 67 | spring-snapshots 68 | Spring Snapshots 69 | https://repo.spring.io/snapshot 70 | 71 | true 72 | 73 | 74 | 75 | 76 | 77 | spring-snapshots 78 | Spring Snapshots 79 | https://repo.spring.io/snapshot 80 | 81 | true 82 | 83 | 84 | 85 | spring-milestones 86 | Spring Milestones 87 | https://repo.spring.io/milestone 88 | 89 | false 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /log4j2/src/main/java/org/springframework/amqp/samples/log4j2/SpringBootAmqpAppenderApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.samples.log4j2; 18 | 19 | import java.io.IOException; 20 | import java.util.Date; 21 | 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | 25 | import org.springframework.amqp.core.ExchangeTypes; 26 | import org.springframework.amqp.rabbit.annotation.Exchange; 27 | import org.springframework.amqp.rabbit.annotation.QueueBinding; 28 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 29 | import org.springframework.boot.SpringApplication; 30 | import org.springframework.boot.autoconfigure.SpringBootApplication; 31 | import org.springframework.context.ConfigurableApplicationContext; 32 | import org.springframework.scheduling.annotation.EnableScheduling; 33 | import org.springframework.scheduling.annotation.Scheduled; 34 | 35 | /** 36 | * @author Artem Bilan 37 | * @since 1.6 38 | */ 39 | @SpringBootApplication 40 | @EnableScheduling 41 | public class SpringBootAmqpAppenderApplication { 42 | 43 | private static final Log logger = LogFactory.getLog(SpringBootAmqpAppenderApplication.class); 44 | 45 | public static void main(String[] args) throws IOException { 46 | ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootAmqpAppenderApplication.class, args); 47 | System.out.println("Hit 'Enter' to terminate"); 48 | System.in.read(); 49 | ctx.close(); 50 | } 51 | 52 | @Scheduled(fixedDelay = 1000, initialDelay = 2000) 53 | public void generateLog() { 54 | logger.info("Log via AmqpAppender: " + new Date()); 55 | } 56 | 57 | @RabbitListener(bindings = @QueueBinding( 58 | exchange = @Exchange(value = "log4j2Sample", type = ExchangeTypes.FANOUT), 59 | value = @org.springframework.amqp.rabbit.annotation.Queue)) 60 | public void echoLogs(String logMessage) { 61 | System.out.println("Logs over Log4J AmqpAppender: " + logMessage); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /log4j2/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM http://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | if ($env:MAVEN_USER_HOME) { 83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" 84 | } 85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 87 | 88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 91 | exit $? 92 | } 93 | 94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 96 | } 97 | 98 | # prepare tmp dir 99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 102 | trap { 103 | if ($TMP_DOWNLOAD_DIR.Exists) { 104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 106 | } 107 | } 108 | 109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 110 | 111 | # Download and Install Apache Maven 112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 113 | Write-Verbose "Downloading from: $distributionUrl" 114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 115 | 116 | $webclient = New-Object System.Net.WebClient 117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 119 | } 120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 122 | 123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 125 | if ($distributionSha256Sum) { 126 | if ($USE_MVND) { 127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 128 | } 129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 132 | } 133 | } 134 | 135 | # unzip and move 136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 138 | try { 139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 140 | } catch { 141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 142 | Write-Error "fail to move MAVEN_HOME" 143 | } 144 | } finally { 145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 147 | } 148 | 149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 150 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | org.springframework.amqp 5 | spring-amqp-samples 6 | Spring AMQP Samples 7 | 3.2.0 8 | pom 9 | 10 | helloworld 11 | stocks 12 | log4j2 13 | spring-rabbit-confirms-returns 14 | spring-rabbit-json 15 | spring-rabbit-global-errorhandler 16 | spring-rabbit-streams 17 | 18 | 19 | UTF-8 20 | 21 | 22 | 23 | https://github.com/SpringSource/spring-amqp-samples 24 | scm:git:git://github.com/SpringSource/spring-amqp-samples.git 25 | scm:git:git://github.com/SpringSource/spring-amqp-samples.git 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /rabbitmq-tutorials/README.md: -------------------------------------------------------------------------------- 1 | # RabbitMQ Tutorial Sample Application 2 | 3 | We are pleased to announce that the Spring AMQP implementations of the [6 RabbitMQ Tutorials][1] are now integrated into that site along with other implementations. 4 | 5 | [1]: https://www.rabbitmq.com/getstarted.html 6 | 7 | For each tutorial, click the `Spring AMQP` link. 8 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/spring-rabbit-confirms-returns/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/README.adoc: -------------------------------------------------------------------------------- 1 | # Configuring for Publisher Confirms and Returns 2 | 3 | This sample demonstrates how to use publisher confirms and returns. 4 | 5 | It uses an auto-delete queue that will be removed after the demo completes. 6 | 7 | It is a Spring Boot application and can be run with normal boot run methods, e.g.: `./mvnw spring-boot:run` 8 | 9 | It shows how to use the `Future` to wait for a delivery confirmation or returned message. 10 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.amqp.samples 7 | spring-rabbit-confirms-returns 8 | 3.2.0 9 | jar 10 | 11 | spring-rabbit-confirms-returns 12 | Demonstrates Configuration for Confirms and Returns 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 3.4.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 17 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-amqp 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | test 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-maven-plugin 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/src/main/java/org/springframework/amqp/samples/confirms/SpringRabbitConfirmsReturnsApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.samples.confirms; 18 | 19 | import java.util.UUID; 20 | import java.util.concurrent.CountDownLatch; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | import org.springframework.amqp.core.Queue; 24 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 25 | import org.springframework.amqp.rabbit.connection.CorrelationData; 26 | import org.springframework.amqp.rabbit.connection.CorrelationData.Confirm; 27 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 28 | import org.springframework.beans.factory.annotation.Autowired; 29 | import org.springframework.boot.ApplicationRunner; 30 | import org.springframework.boot.SpringApplication; 31 | import org.springframework.boot.autoconfigure.SpringBootApplication; 32 | import org.springframework.context.ConfigurableApplicationContext; 33 | import org.springframework.context.annotation.Bean; 34 | 35 | @SpringBootApplication 36 | public class SpringRabbitConfirmsReturnsApplication { 37 | 38 | private static final String QUEUE = "spring.publisher.sample"; 39 | 40 | public static void main(String[] args) throws Exception { 41 | ConfigurableApplicationContext context = SpringApplication.run(SpringRabbitConfirmsReturnsApplication.class, 42 | args); 43 | context.close(); 44 | } 45 | 46 | @Autowired 47 | private RabbitTemplate rabbitTemplate; 48 | 49 | private final CountDownLatch listenLatch = new CountDownLatch(1); 50 | 51 | private void runDemo() throws Exception { 52 | setupCallbacks(); 53 | // send a message to the default exchange to be routed to the queue 54 | CorrelationData correlationData = new CorrelationData("Correlation for message 1"); 55 | this.rabbitTemplate.convertAndSend("", QUEUE, "foo", correlationData); 56 | Confirm confirm = correlationData.getFuture().get(10, TimeUnit.SECONDS); 57 | System.out.println("Confirm received for good delivery, ack = " + confirm.isAck()); 58 | if (this.listenLatch.await(10, TimeUnit.SECONDS)) { 59 | System.out.println("Message received by listener"); 60 | } 61 | else { 62 | System.out.println("Message NOT received by listener"); 63 | } 64 | // send a message to the default exchange to be routed to a non-existent queue 65 | correlationData = new CorrelationData("Correlation for message 2"); 66 | this.rabbitTemplate.convertAndSend("", QUEUE + QUEUE, "bar", message -> { 67 | System.out.println("Message after conversion: " + message); 68 | return message; 69 | }, correlationData); 70 | confirm = correlationData.getFuture().get(10, TimeUnit.SECONDS); 71 | System.out.println("Confirm received for send to missing queue, ack = " + confirm.isAck()); 72 | System.out.println("Return received:" + correlationData.getReturned()); 73 | correlationData = new CorrelationData("Correlation for message 3"); 74 | // send to non-existent exchange - expect nack 75 | this.rabbitTemplate.convertAndSend(UUID.randomUUID().toString(), QUEUE, "baz", correlationData); 76 | confirm = correlationData.getFuture().get(10, TimeUnit.SECONDS); 77 | System.out.println("Confirm received for send to missing exchange, ack = " + confirm.isAck()); 78 | } 79 | 80 | private void setupCallbacks() { 81 | /* 82 | * Confirms/returns enabled in application.properties - add the callbacks here. 83 | */ 84 | this.rabbitTemplate.setConfirmCallback((correlation, ack, reason) -> { 85 | if (correlation != null) { 86 | System.out.println("Received " + (ack ? " ack " : " nack ") + "for correlation: " + correlation); 87 | } 88 | }); 89 | this.rabbitTemplate.setReturnsCallback(returned -> { 90 | System.out.println("Returned: " + returned.getMessage() + "\nreplyCode: " + returned.getReplyCode() 91 | + "\nreplyText: " + returned.getReplyText() + "\nexchange/rk: " 92 | + returned.getExchange() + "/" + returned.getRoutingKey()); 93 | }); 94 | } 95 | 96 | 97 | @Bean 98 | public ApplicationRunner runner() { 99 | return args -> runDemo(); 100 | } 101 | 102 | @Bean 103 | public Queue queue() { 104 | return new Queue(QUEUE, false, false, true); 105 | } 106 | 107 | @RabbitListener(queues = QUEUE) 108 | public void listen(String in) { 109 | System.out.println("Listener received: " + in); 110 | this.listenLatch.countDown(); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rabbitmq.publisher-confirm-type=correlated 2 | spring.rabbitmq.publisher-returns=true 3 | 4 | spring.rabbitmq.template.mandatory=true 5 | -------------------------------------------------------------------------------- /spring-rabbit-confirms-returns/src/test/java/org/springframework/amqp/samples/confirms/SpringRabbitConfirmsReturnsApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017-2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.samples.confirms; 18 | 19 | import org.junit.jupiter.api.Test; 20 | 21 | import org.springframework.boot.test.context.SpringBootTest; 22 | 23 | @SpringBootTest 24 | public class SpringRabbitConfirmsReturnsApplicationTests { 25 | 26 | @Test 27 | public void contextLoads() { 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/spring-rabbit-global-errorhandler/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/README.adoc: -------------------------------------------------------------------------------- 1 | # Configuring a Global Error Handler for @RabbitListener s 2 | 3 | This sample demonstrates how to add a global error handler to `@RabbitListener` methods. 4 | 5 | It uses an auto-delete queue that will be removed after the demo completes. 6 | 7 | The error handler is the same as the default (`ConditionalRejectingErrorHandler`) but with a custom `FatalExceptionStrategy` 8 | that extends the default and logs the failed message. 9 | 10 | NOTE: Such a simple handler is not generally needed since the framework will log the failed message itself; for a real 11 | application, some additional action might be taken, for example write the bad message to a database. 12 | 13 | A JSON message converter is used; the sample sends one "good" message, and one bad one, which fails message conversion. 14 | Message conversion is considered fatal and the message is not requeued. 15 | 16 | It is a Spring Boot application and can be run with normal boot run methods, e.g.: `./mvnw spring-boot:run` 17 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | spring-rabbit-global-errorhandler 8 | 3.2.0 9 | jar 10 | 11 | spring-rabbit-global-errorhandler 12 | Shows how to configure a custom error handler applied to listener beans 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 3.4.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 17 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-amqp 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-logging 36 | 37 | 38 | 39 | 40 | 41 | com.fasterxml.jackson.core 42 | jackson-databind 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/src/main/java/org/springframework/amqp/samples/errorhandler/Application.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.errorhandler; 2 | 3 | import org.slf4j.Logger; 4 | 5 | import org.springframework.amqp.core.Message; 6 | import org.springframework.amqp.core.Queue; 7 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 8 | import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; 9 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 10 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 11 | import org.springframework.amqp.rabbit.listener.ConditionalRejectingErrorHandler; 12 | import org.springframework.amqp.rabbit.support.ListenerExecutionFailedException; 13 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 14 | import org.springframework.amqp.support.converter.MessageConverter; 15 | import org.springframework.boot.SpringApplication; 16 | import org.springframework.boot.autoconfigure.SpringBootApplication; 17 | import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer; 18 | import org.springframework.context.ConfigurableApplicationContext; 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.util.ErrorHandler; 21 | 22 | @SpringBootApplication 23 | public class Application { 24 | 25 | private static final String TEST_QUEUE = "spring.amqp.global.error.handler.demo"; 26 | 27 | private final Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); 28 | 29 | public static void main(String[] args) throws Exception { 30 | ConfigurableApplicationContext context = SpringApplication.run(Application.class, args); 31 | context.getBean(Application.class).runDemo(context.getBean(RabbitTemplate.class)); 32 | context.close(); 33 | } 34 | 35 | private void runDemo(RabbitTemplate template) throws Exception { 36 | template.convertAndSend(TEST_QUEUE, new Foo("bar")); 37 | template.convertAndSend(TEST_QUEUE, new Foo("bar"), m -> { 38 | return new Message("some bad json".getBytes(), m.getMessageProperties()); 39 | }); 40 | Thread.sleep(5000); 41 | } 42 | 43 | @RabbitListener(queues = TEST_QUEUE) 44 | public void handle(Foo in) { 45 | logger.info("Received: " + in); 46 | } 47 | 48 | @Bean 49 | public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory, 50 | SimpleRabbitListenerContainerFactoryConfigurer configurer) { 51 | SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); 52 | configurer.configure(factory, connectionFactory); 53 | factory.setErrorHandler(errorHandler()); 54 | return factory; 55 | } 56 | 57 | @Bean 58 | public ErrorHandler errorHandler() { 59 | return new ConditionalRejectingErrorHandler(new MyFatalExceptionStrategy()); 60 | } 61 | 62 | @Bean 63 | public Queue queue() { 64 | return new Queue(TEST_QUEUE, false, false, true); 65 | } 66 | 67 | @Bean 68 | public MessageConverter jsonConverter() { 69 | return new Jackson2JsonMessageConverter(); 70 | } 71 | 72 | public static class MyFatalExceptionStrategy extends ConditionalRejectingErrorHandler.DefaultExceptionStrategy { 73 | 74 | private final Logger logger = org.slf4j.LoggerFactory.getLogger(getClass()); 75 | 76 | @Override 77 | public boolean isFatal(Throwable t) { 78 | if (t instanceof ListenerExecutionFailedException) { 79 | ListenerExecutionFailedException lefe = (ListenerExecutionFailedException) t; 80 | logger.error("Failed to process inbound message from queue " 81 | + lefe.getFailedMessage().getMessageProperties().getConsumerQueue() 82 | + "; failed message: " + lefe.getFailedMessage(), t); 83 | } 84 | return super.isFatal(t); 85 | } 86 | 87 | } 88 | 89 | public static class Foo { 90 | 91 | private String foo; 92 | 93 | public Foo() { 94 | super(); 95 | } 96 | 97 | public Foo(String foo) { 98 | this.foo = foo; 99 | } 100 | 101 | public String getFoo() { 102 | return this.foo; 103 | } 104 | 105 | public void setFoo(String foo) { 106 | this.foo = foo; 107 | } 108 | 109 | @Override 110 | public String toString() { 111 | return "Foo [foo=" + this.foo + "]"; 112 | } 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | listener: 4 | simple: 5 | retry: 6 | enabled: false 7 | initial-interval: 2000 8 | multiplier: 1.5 9 | max-interval: 10000 10 | max-attempts: 3 11 | -------------------------------------------------------------------------------- /spring-rabbit-global-errorhandler/src/test/java/org/springframework/amqp/samples/errorhandler/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.errorhandler; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | public class ApplicationTests { 9 | 10 | @Test 11 | public void contextLoads() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-rabbit-json/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /spring-rabbit-json/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/spring-rabbit-json/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-rabbit-json/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /spring-rabbit-json/README.adoc: -------------------------------------------------------------------------------- 1 | # Receiving JSON From a Non-Spring Application 2 | 3 | Spring AMQP applications communicating over AMQP using JSON add type information to message headers to enable the receiving application to convert the JSON to a class instance. 4 | 5 | This sample demonstrates techniques to use for such conversion when the sending application is not a Spring app or if you wish to convert to a different type when receiving messages. 6 | 7 | - Inferred type from `@RabbitListener` methods 8 | - Parameterized types in template `receiveAndConvert()` methods 9 | - `ClassMapper` id mapping configuration with a legacy POJO listener. 10 | 11 | It is a Spring Boot application and can be run with normal boot run methods, e.g.: `./mvnw spring-boot:run` 12 | -------------------------------------------------------------------------------- /spring-rabbit-json/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /spring-rabbit-json/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /spring-rabbit-json/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.example 7 | spring-rabbit-json 8 | 3.2.0 9 | jar 10 | 11 | spring-rabbit-json 12 | Receiving JSON from non-Spring Applications 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 3.4.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 17 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-amqp 32 | 33 | 34 | 35 | com.fasterxml.jackson.core 36 | jackson-databind 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-maven-plugin 51 | 52 | 53 | 54 | 55 | 56 | repository.springframework.maven.snapshots 57 | Spring Framework Repository Including Snapshots 58 | https://repo.spring.io/snapshot 59 | 60 | true 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /spring-rabbit-json/src/main/java/org/springframework/amqp/samples/json/Application.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.json; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import org.springframework.amqp.core.AmqpAdmin; 9 | import org.springframework.amqp.core.AnonymousQueue; 10 | import org.springframework.amqp.core.Message; 11 | import org.springframework.amqp.core.MessageBuilder; 12 | import org.springframework.amqp.core.MessagePropertiesBuilder; 13 | import org.springframework.amqp.core.Queue; 14 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 15 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 16 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 17 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 18 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; 19 | import org.springframework.amqp.support.converter.DefaultClassMapper; 20 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 21 | import org.springframework.amqp.support.converter.MessageConverter; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.SpringApplication; 24 | import org.springframework.boot.autoconfigure.SpringBootApplication; 25 | import org.springframework.context.ConfigurableApplicationContext; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.core.ParameterizedTypeReference; 28 | 29 | @SpringBootApplication 30 | public class Application { 31 | 32 | private static final String INFERRED_FOO_QUEUE = "sample.inferred.foo"; 33 | 34 | private static final String INFERRED_BAR_QUEUE = "sample.inferred.bar"; 35 | 36 | private static final String RECEIVE_AND_CONVERT_QUEUE = "sample.receive.and.convert"; 37 | 38 | private static final String MAPPED_QUEUE = "sample.mapped"; 39 | 40 | public static void main(String[] args) throws Exception { 41 | ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); 42 | ctx.getBean(Application.class).runDemo(ctx.getBean("rabbitTemplate", RabbitTemplate.class), 43 | ctx.getBean("jsonRabbitTemplate", RabbitTemplate.class)); 44 | ctx.close(); 45 | } 46 | 47 | @Autowired 48 | private AmqpAdmin rabbitAdmin; 49 | 50 | private volatile CountDownLatch latch = new CountDownLatch(2); 51 | 52 | public void runDemo(RabbitTemplate rabbitTemplate, RabbitTemplate jsonRabbitTemplate) throws Exception { 53 | String json = "{\"foo\" : \"value\" }"; 54 | Message jsonMessage = MessageBuilder.withBody(json.getBytes()) 55 | .andProperties(MessagePropertiesBuilder.newInstance().setContentType("application/json") 56 | .build()).build(); 57 | 58 | // inferred type 59 | 60 | rabbitTemplate.send(INFERRED_FOO_QUEUE, jsonMessage); 61 | rabbitTemplate.send(INFERRED_BAR_QUEUE, jsonMessage); 62 | this.latch.await(10, TimeUnit.SECONDS); 63 | 64 | // convertAndReceive with type 65 | 66 | rabbitTemplate.send(RECEIVE_AND_CONVERT_QUEUE, jsonMessage); 67 | rabbitTemplate.send(RECEIVE_AND_CONVERT_QUEUE, jsonMessage); 68 | 69 | Foo foo = jsonRabbitTemplate.receiveAndConvert(RECEIVE_AND_CONVERT_QUEUE, 10_000, 70 | new ParameterizedTypeReference() { }); 71 | System.out.println("Expected a Foo, got a " + foo); 72 | Bar bar = jsonRabbitTemplate.receiveAndConvert(RECEIVE_AND_CONVERT_QUEUE, 10_000, 73 | new ParameterizedTypeReference() { }); 74 | System.out.println("Expected a Bar, got a " + bar); 75 | 76 | // Mapped type information with legacy POJO listener 77 | 78 | this.latch = new CountDownLatch(2); 79 | jsonMessage.getMessageProperties().setHeader("__TypeId__", "foo"); 80 | rabbitTemplate.send(MAPPED_QUEUE, jsonMessage); 81 | jsonMessage.getMessageProperties().setHeader("__TypeId__", "bar"); 82 | rabbitTemplate.send(MAPPED_QUEUE, jsonMessage); 83 | this.latch.await(10, TimeUnit.SECONDS); 84 | 85 | this.rabbitAdmin.deleteQueue(RECEIVE_AND_CONVERT_QUEUE); 86 | } 87 | 88 | @RabbitListener(queues = INFERRED_FOO_QUEUE) 89 | public void listenForAFoo(Foo foo) { 90 | System.out.println("Expected a Foo, got a " + foo); 91 | this.latch.countDown(); 92 | } 93 | 94 | @RabbitListener(queues = INFERRED_BAR_QUEUE) 95 | public void listenForAFoo(Bar bar) { 96 | System.out.println("Expected a Bar, got a " + bar); 97 | this.latch.countDown(); 98 | } 99 | 100 | @Bean 101 | public SimpleMessageListenerContainer legacyPojoListener(ConnectionFactory connectionFactory) { 102 | SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); 103 | container.setQueueNames(MAPPED_QUEUE); 104 | MessageListenerAdapter messageListener = new MessageListenerAdapter(new Object() { 105 | 106 | @SuppressWarnings("unused") 107 | public void handleMessage(Object object) { 108 | System.out.println("Got a " + object); 109 | Application.this.latch.countDown(); 110 | } 111 | 112 | }); 113 | Jackson2JsonMessageConverter jsonConverter = new Jackson2JsonMessageConverter(); 114 | jsonConverter.setClassMapper(classMapper()); 115 | messageListener.setMessageConverter(jsonConverter); 116 | container.setMessageListener(messageListener); 117 | return container; 118 | } 119 | 120 | @Bean 121 | public DefaultClassMapper classMapper() { 122 | DefaultClassMapper classMapper = new DefaultClassMapper(); 123 | Map> idClassMapping = new HashMap<>(); 124 | idClassMapping.put("foo", Foo.class); 125 | idClassMapping.put("bar", Bar.class); 126 | classMapper.setIdClassMapping(idClassMapping); 127 | return classMapper; 128 | } 129 | 130 | @Bean 131 | public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { 132 | return new RabbitTemplate(connectionFactory); 133 | } 134 | 135 | @Bean 136 | public RabbitTemplate jsonRabbitTemplate(ConnectionFactory connectionFactory) { 137 | RabbitTemplate template = new RabbitTemplate(connectionFactory); 138 | template.setMessageConverter(jsonConverter()); 139 | return template; 140 | } 141 | 142 | @Bean 143 | public MessageConverter jsonConverter() { 144 | return new Jackson2JsonMessageConverter(); 145 | } 146 | 147 | @Bean 148 | public Queue inferredFoo() { 149 | return new AnonymousQueue(() -> INFERRED_FOO_QUEUE); 150 | } 151 | 152 | @Bean 153 | public Queue inferredBar() { 154 | return new AnonymousQueue(() -> INFERRED_BAR_QUEUE); 155 | } 156 | 157 | @Bean 158 | public Queue convertAndReceive() { 159 | return new Queue(RECEIVE_AND_CONVERT_QUEUE); 160 | } 161 | 162 | @Bean 163 | public Queue mapped() { 164 | return new AnonymousQueue(() -> MAPPED_QUEUE); 165 | } 166 | 167 | public static class Foo { 168 | 169 | private String foo; 170 | 171 | public Foo() { 172 | super(); 173 | } 174 | 175 | public Foo(String foo) { 176 | this.foo = foo; 177 | } 178 | 179 | public String getFoo() { 180 | return this.foo; 181 | } 182 | 183 | public void setFoo(String foo) { 184 | this.foo = foo; 185 | } 186 | 187 | @Override 188 | public String toString() { 189 | return getClass().getSimpleName() + " [foo=" + this.foo + "]"; 190 | } 191 | 192 | } 193 | 194 | public static class Bar extends Foo { 195 | 196 | public Bar() { 197 | super(); 198 | } 199 | 200 | public Bar(String foo) { 201 | super(foo); 202 | } 203 | 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /spring-rabbit-json/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/spring-rabbit-json/src/main/resources/application.properties -------------------------------------------------------------------------------- /spring-rabbit-json/src/test/java/org/springframework/amqp/samples/json/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.json; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | 7 | @SpringBootTest 8 | public class ApplicationTests { 9 | 10 | @Test 11 | public void contextLoads() { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /spring-rabbit-streams/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/spring-rabbit-streams/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /spring-rabbit-streams/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 3 | -------------------------------------------------------------------------------- /spring-rabbit-streams/README.adoc: -------------------------------------------------------------------------------- 1 | = Interaction with RabbitMQ Streams 2 | 3 | The `spring-rabbit-stream` provides Spring-friendly API over https://www.rabbitmq.com/docs/streams[RabbitMQ Streams] Java client. 4 | 5 | The https://www.rabbitmq.com/docs/stream[`rabbitmq_stream` plugin] must be enabled on RabbitMQ broker. 6 | 7 | Together with Spring Boot auto-configuration for https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#messaging.amqp[Spring AMQP], this sample demonstrates a simple production of 100 messages to `sample-spring-amqp-stream` RabbitMQ queue of type `stream`. 8 | This queue is created automatically by the application using `StreamAdmin` API. 9 | Then this sample registers 10 `@RabbitListener` instances dynamically (which are `spring.rabbitmq.listener.type=stream`) to demonstrate fan-out capability of RabbitMQ Streams. 10 | 11 | The `SpringRabbitStreamsApplicationTests` ensures that all the listeners in the application report their consumption from the `spring-rabbit-stream` into logs for the last `Value #99` data. 12 | 13 | See more information in the https://docs.spring.io/spring-amqp/reference/stream.html[Reference Manual]. 14 | -------------------------------------------------------------------------------- /spring-rabbit-streams/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.0 9 | 10 | 11 | org.springframework.amqp.samples 12 | spring-rabbit-streams 13 | 3.2.0 14 | spring-rabbit-streams 15 | spring-rabbit-streams 16 | 17 | 17 18 | ${project.version} 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-amqp 24 | 25 | 26 | org.springframework.amqp 27 | spring-rabbit-stream 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-test 32 | test 33 | 34 | 35 | org.springframework.amqp 36 | spring-rabbit-test 37 | test 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-maven-plugin 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /spring-rabbit-streams/src/main/java/org/springframework/amqp/samples/streams/SpringRabbitStreamsApplication.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.streams; 2 | 3 | import java.time.Duration; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.stream.IntStream; 6 | 7 | import com.rabbitmq.stream.Environment; 8 | import com.rabbitmq.stream.OffsetSpecification; 9 | import jakarta.annotation.PostConstruct; 10 | import org.apache.commons.logging.Log; 11 | import org.apache.commons.logging.LogFactory; 12 | 13 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 14 | import org.springframework.amqp.rabbit.config.ContainerCustomizer; 15 | import org.springframework.beans.BeansException; 16 | import org.springframework.beans.factory.BeanFactory; 17 | import org.springframework.beans.factory.BeanFactoryAware; 18 | import org.springframework.beans.factory.BeanNameAware; 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 21 | import org.springframework.boot.ApplicationRunner; 22 | import org.springframework.boot.SpringApplication; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | import org.springframework.context.annotation.Bean; 25 | import org.springframework.rabbit.stream.listener.StreamListenerContainer; 26 | import org.springframework.rabbit.stream.producer.RabbitStreamOperations; 27 | import org.springframework.rabbit.stream.support.StreamAdmin; 28 | 29 | @SpringBootApplication 30 | public class SpringRabbitStreamsApplication implements BeanFactoryAware { 31 | 32 | private AutowireCapableBeanFactory beanFactory; 33 | 34 | public static void main(String[] args) { 35 | SpringApplication.run(SpringRabbitStreamsApplication.class, args); 36 | } 37 | 38 | @Override 39 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 40 | this.beanFactory = (AutowireCapableBeanFactory) beanFactory; 41 | } 42 | 43 | @PostConstruct 44 | public void addStreamConsumers() { 45 | for (int i = 0; i < 10; i++) { 46 | this.beanFactory.initializeBean(new SampleRabbitStreamListener(), 47 | SampleRabbitStreamListener.class.getSimpleName() + "#" + i); 48 | } 49 | } 50 | 51 | @Bean 52 | ApplicationRunner streamProducer(RabbitStreamOperations rabbitStreamOperations) { 53 | return args -> { 54 | CompletableFuture[] sendResults = 55 | IntStream.range(0, 100) 56 | .boxed() 57 | .map((value) -> "Value #" + value) 58 | .map(rabbitStreamOperations::convertAndSend) 59 | .toArray(CompletableFuture[]::new); 60 | 61 | CompletableFuture.allOf(sendResults).join(); 62 | }; 63 | 64 | } 65 | 66 | @Bean 67 | StreamAdmin streamAdmin(Environment streamEnvironment, @Value("${spring.rabbitmq.stream.name}") String streamName) { 68 | return new StreamAdmin(streamEnvironment, sc -> sc.stream(streamName).maxAge(Duration.ofMinutes(1)).create()); 69 | } 70 | 71 | @Bean 72 | ContainerCustomizer streamListenerContainerContainerCustomizer() { 73 | return (container) -> 74 | container.setConsumerCustomizer((listenerId, consumerBuilder) -> 75 | consumerBuilder.offset(OffsetSpecification.last())); 76 | } 77 | 78 | private static class SampleRabbitStreamListener implements BeanNameAware { 79 | 80 | private static final Log LOG = LogFactory.getLog(SampleRabbitStreamListener.class); 81 | 82 | private String beanName; 83 | 84 | @Override 85 | public void setBeanName(String name) { 86 | this.beanName = name; 87 | } 88 | 89 | @RabbitListener(queues = "${spring.rabbitmq.stream.name}") 90 | void listen(String data) { 91 | LOG.info(this.beanName + " received: " + data); 92 | } 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /spring-rabbit-streams/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.rabbitmq.listener.type=stream 2 | spring.rabbitmq.stream.name=sample-spring-amqp-stream 3 | -------------------------------------------------------------------------------- /spring-rabbit-streams/src/test/java/org/springframework/amqp/samples/streams/SpringRabbitStreamsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package org.springframework.amqp.samples.streams; 2 | 3 | import java.util.stream.IntStream; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.boot.test.system.CapturedOutput; 10 | import org.springframework.boot.test.system.OutputCaptureExtension; 11 | import org.springframework.test.annotation.DirtiesContext; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | import static org.awaitility.Awaitility.await; 15 | 16 | @SpringBootTest 17 | @ExtendWith(OutputCaptureExtension.class) 18 | @DirtiesContext 19 | class SpringRabbitStreamsApplicationTests { 20 | 21 | @Test 22 | void verifyAllStreamListenerReceivesAllData(CapturedOutput output) { 23 | IntStream.range(0, 10) 24 | .forEach((index) -> 25 | await().untilAsserted(() -> 26 | assertThat(output.getOut()) 27 | .contains("SampleRabbitStreamListener#" + index + " received: Value #99"))); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /stocks/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/.DS_Store -------------------------------------------------------------------------------- /stocks/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.springframework.samples.spring 6 | spring-rabbit-stocks 7 | 3.2.0 8 | war 9 | Spring Rabbit Stocks 10 | https://www.spring.io 11 | 12 | 15 | 16 | 17 | true 18 | 6.2.1 19 | 3.2.1 20 | UTF-8 21 | 17 22 | 23 | 24 | 25 | 26 | 27 | com.fasterxml.jackson 28 | jackson-bom 29 | 2.18.2 30 | import 31 | pom 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.springframework.amqp 39 | spring-rabbit 40 | ${spring.amqp.version} 41 | 42 | 43 | 44 | org.springframework 45 | spring-context-support 46 | ${spring.framework.version} 47 | runtime 48 | 49 | 50 | org.springframework 51 | spring-oxm 52 | ${spring.framework.version} 53 | 54 | 55 | org.springframework 56 | spring-tx 57 | ${spring.framework.version} 58 | 59 | 60 | org.springframework 61 | spring-webmvc 62 | ${spring.framework.version} 63 | 64 | 65 | jakarta.servlet 66 | jakarta.servlet-api 67 | 6.0.0 68 | provided 69 | 70 | 71 | org.apache.taglibs 72 | taglibs-standard-spec 73 | 1.2.5 74 | runtime 75 | 76 | 77 | org.apache.taglibs 78 | taglibs-standard-impl 79 | 1.2.5 80 | runtime 81 | 82 | 83 | org.aspectj 84 | aspectjrt 85 | 1.9.22.1 86 | 87 | 88 | org.aspectj 89 | aspectjweaver 90 | 1.9.22.1 91 | 92 | 93 | 94 | com.fasterxml.jackson.core 95 | jackson-databind 96 | runtime 97 | 98 | 99 | 100 | org.springframework.amqp 101 | spring-rabbit-test 102 | ${spring.amqp.version} 103 | test 104 | 105 | 106 | 107 | junit 108 | junit 109 | 4.13.2 110 | test 111 | 112 | 113 | 114 | org.apache.logging.log4j 115 | log4j-core 116 | 2.24.3 117 | 118 | 119 | 120 | org.apache.logging.log4j 121 | log4j-jcl 122 | 2.24.3 123 | runtime 124 | 125 | 126 | org.apache.logging.log4j 127 | log4j-slf4j-impl 128 | 2.24.3 129 | 130 | 131 | com.jgoodies 132 | forms 133 | 1.2.1 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | org.eclipse.jetty 142 | jetty-maven-plugin 143 | 11.0.24 144 | 145 | 146 | org.apache.maven.plugins 147 | maven-compiler-plugin 148 | 3.13.0 149 | 150 | 17 151 | 17 152 | 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-surefire-plugin 157 | 3.5.2 158 | 159 | 160 | 161 | **/*Tests.java 162 | 163 | 164 | **/Abstract*.java 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/config/AbstractStockAppRabbitConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.config; 18 | 19 | import org.springframework.amqp.core.AmqpAdmin; 20 | import org.springframework.amqp.core.TopicExchange; 21 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 22 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 23 | import org.springframework.amqp.rabbit.core.RabbitAdmin; 24 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 25 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; 26 | import org.springframework.amqp.support.converter.MessageConverter; 27 | import org.springframework.beans.factory.annotation.Value; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.context.annotation.Configuration; 30 | 31 | /** 32 | * Provides shared configuration between Client and Server. 33 | *

The abstract method configureRabbitTemplate lets the Client and Server further customize 34 | * the rabbit template to their specific needs. 35 | * 36 | * @author Mark Pollack 37 | * @author Mark Fisher 38 | * @author Gary Russell 39 | */ 40 | @Configuration 41 | public abstract class AbstractStockAppRabbitConfiguration { 42 | 43 | /** 44 | * Shared topic exchange used for publishing any market data (e.g. stock quotes) 45 | */ 46 | protected static String MARKET_DATA_EXCHANGE_NAME = "app.stock.marketdata"; 47 | 48 | /** 49 | * The server-side consumer's queue that provides point-to-point semantics for stock requests. 50 | */ 51 | protected static String STOCK_REQUEST_QUEUE_NAME = "app.stock.request"; 52 | 53 | /** 54 | * Key that clients will use to send to the stock request queue via the default direct exchange. 55 | */ 56 | protected static String STOCK_REQUEST_ROUTING_KEY = STOCK_REQUEST_QUEUE_NAME; 57 | 58 | @Value("${amqp.port:5672}") 59 | private final int port = 5672; 60 | 61 | 62 | protected abstract void configureRabbitTemplate(RabbitTemplate template); 63 | 64 | @Bean 65 | public ConnectionFactory connectionFactory() { 66 | //TODO make it possible to customize in subclasses. 67 | CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost"); 68 | connectionFactory.setUsername("guest"); 69 | connectionFactory.setPassword("guest"); 70 | connectionFactory.setPort(port); 71 | return connectionFactory; 72 | } 73 | 74 | @Bean 75 | public RabbitTemplate rabbitTemplate() { 76 | RabbitTemplate template = new RabbitTemplate(connectionFactory()); 77 | template.setMessageConverter(jsonMessageConverter()); 78 | configureRabbitTemplate(template); 79 | return template; 80 | } 81 | 82 | @Bean 83 | public MessageConverter jsonMessageConverter() { 84 | return new Jackson2JsonMessageConverter(); 85 | } 86 | 87 | @Bean 88 | public TopicExchange marketDataExchange() { 89 | return new TopicExchange(MARKET_DATA_EXCHANGE_NAME); 90 | } 91 | 92 | /** 93 | * @return the admin bean that can declare queues etc. 94 | */ 95 | @Bean 96 | public AmqpAdmin amqpAdmin() { 97 | RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory()); 98 | return rabbitAdmin ; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/config/RoutingKey.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.config; 18 | 19 | /** 20 | * Enumerations for the RoutingKeys used in the application to allow for a more fluent API 21 | * style when configuring the broker in code. 22 | * 23 | * @author Mark Pollack 24 | */ 25 | public enum RoutingKey { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/config/client/RabbitClientConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.config.client; 18 | 19 | 20 | import org.springframework.amqp.core.AcknowledgeMode; 21 | import org.springframework.amqp.core.AmqpAdmin; 22 | import org.springframework.amqp.core.AnonymousQueue; 23 | import org.springframework.amqp.core.Binding; 24 | import org.springframework.amqp.core.BindingBuilder; 25 | import org.springframework.amqp.core.Queue; 26 | import org.springframework.amqp.rabbit.core.RabbitAdmin; 27 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 28 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 29 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; 30 | import org.springframework.amqp.rabbit.stocks.config.AbstractStockAppRabbitConfiguration; 31 | import org.springframework.amqp.rabbit.stocks.gateway.RabbitStockServiceGateway; 32 | import org.springframework.amqp.rabbit.stocks.gateway.StockServiceGateway; 33 | import org.springframework.amqp.rabbit.stocks.handler.ClientHandler; 34 | import org.springframework.beans.factory.annotation.Autowired; 35 | import org.springframework.beans.factory.annotation.Value; 36 | import org.springframework.context.annotation.Bean; 37 | import org.springframework.context.annotation.Configuration; 38 | 39 | /** 40 | * Configures RabbitTemplate and creates the Trader queue and binding for the client. 41 | * 42 | * @author Mark Pollack 43 | * @author Mark Fisher 44 | * @author Gary Russell 45 | */ 46 | @Configuration 47 | public class RabbitClientConfiguration extends AbstractStockAppRabbitConfiguration { 48 | 49 | @Value("${stocks.quote.pattern}") 50 | private String marketDataRoutingKey; 51 | 52 | @Autowired 53 | private ClientHandler clientHandler; 54 | 55 | /** 56 | * The client's template will by default send to the exchange defined 57 | * in {@link org.springframework.amqp.rabbit.config.AbstractRabbitConfiguration#rabbitTemplate()} 58 | * with the routing key {@link AbstractStockAppRabbitConfiguration#STOCK_REQUEST_QUEUE_NAME} 59 | *

60 | * The default exchange will delivery to a queue whose name matches the routing key value. 61 | */ 62 | @Override 63 | public void configureRabbitTemplate(RabbitTemplate rabbitTemplate) { 64 | rabbitTemplate.setRoutingKey(STOCK_REQUEST_QUEUE_NAME); 65 | } 66 | 67 | @Bean 68 | public StockServiceGateway stockServiceGateway() { 69 | RabbitStockServiceGateway gateway = new RabbitStockServiceGateway(); 70 | gateway.setRabbitOperations(rabbitTemplate()); 71 | gateway.setDefaultReplyTo(traderJoeQueue().getName()); 72 | return gateway; 73 | } 74 | 75 | @Bean 76 | public SimpleMessageListenerContainer messageListenerContainer() { 77 | SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory()); 78 | container.setQueues(marketDataQueue(), traderJoeQueue()); 79 | container.setMessageListener(messageListenerAdapter()); 80 | container.setAcknowledgeMode(AcknowledgeMode.AUTO); 81 | return container; 82 | 83 | //container(using(connectionFactory()).listenToQueues(marketDataQueue(), traderJoeQueue()).withListener(messageListenerAdapter()). 84 | } 85 | 86 | @Bean 87 | public MessageListenerAdapter messageListenerAdapter() { 88 | return new MessageListenerAdapter(clientHandler, jsonMessageConverter()); 89 | } 90 | 91 | 92 | // Broker Configuration 93 | 94 | // @PostContruct 95 | // public void declareClientBrokerConfiguration() { 96 | // declare(marketDataQueue); 97 | // declare(new Binding(marketDataQueue, MARKET_DATA_EXCHANGE, marketDataRoutingKey)); 98 | // declare(traderJoeQueue); 99 | // // no need to bind traderJoeQueue as it is automatically bound to the default direct exchanage, which is what we will use 100 | // 101 | // //add as many declare statements as needed like a script. 102 | // } 103 | 104 | @Bean 105 | public Queue marketDataQueue() { 106 | return new AnonymousQueue(); 107 | } 108 | 109 | /** 110 | * Binds to the market data exchange. Interested in any stock quotes. 111 | */ 112 | @Bean 113 | public Binding marketDataBinding() { 114 | return BindingBuilder.bind(marketDataQueue()).to(marketDataExchange()).with(marketDataRoutingKey); 115 | } 116 | 117 | /** 118 | * This queue does not need a binding, since it relies on the default exchange. 119 | */ 120 | @Bean 121 | public Queue traderJoeQueue() { 122 | return new AnonymousQueue(); 123 | } 124 | 125 | @Bean 126 | public AmqpAdmin rabbitAdmin() { 127 | return new RabbitAdmin(connectionFactory()); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/config/server/RabbitServerConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.config.server; 18 | 19 | import org.springframework.amqp.core.Queue; 20 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 21 | import org.springframework.amqp.rabbit.stocks.config.AbstractStockAppRabbitConfiguration; 22 | import org.springframework.context.annotation.Bean; 23 | import org.springframework.context.annotation.Configuration; 24 | 25 | /** 26 | * Configures RabbitTemplate for the server. 27 | * 28 | * @author Mark Pollack 29 | * @author Mark Fisher 30 | */ 31 | @Configuration 32 | public class RabbitServerConfiguration extends AbstractStockAppRabbitConfiguration { 33 | 34 | /** 35 | * The server's template will by default send to the topic exchange named 36 | * {@link AbstractStockAppRabbitConfiguration#MARKET_DATA_EXCHANGE_NAME}. 37 | */ 38 | public void configureRabbitTemplate(RabbitTemplate rabbitTemplate) { 39 | rabbitTemplate.setExchange(MARKET_DATA_EXCHANGE_NAME); 40 | } 41 | 42 | /** 43 | * We don't need to define any binding for the stock request queue, since it's relying 44 | * on the default (no-name) direct exchange to which every queue is implicitly bound. 45 | */ 46 | @Bean 47 | public Queue stockRequestQueue() { 48 | return new Queue(STOCK_REQUEST_QUEUE_NAME); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/domain/Quote.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | package org.springframework.amqp.rabbit.stocks.domain; 15 | 16 | import java.text.DateFormat; 17 | import java.util.Date; 18 | 19 | /** 20 | * Domain object representing a stock quote. 21 | * 22 | * @author Mark Fisher 23 | */ 24 | public class Quote { 25 | 26 | private Stock stock; 27 | private String price; 28 | private long timestamp; 29 | 30 | private DateFormat format = DateFormat.getTimeInstance(); 31 | 32 | public Quote() { 33 | this(null, null); 34 | } 35 | 36 | public Quote(Stock stock, String price) { 37 | this(stock, price, new Date().getTime()); 38 | } 39 | 40 | public Quote(Stock stock, String price, long timestamp) { 41 | this.stock = stock; 42 | this.price = price; 43 | this.timestamp = timestamp; 44 | } 45 | 46 | public Stock getStock() { 47 | return this.stock; 48 | } 49 | 50 | public void setStock(Stock stock) { 51 | this.stock = stock; 52 | } 53 | 54 | public String getPrice() { 55 | return price; 56 | } 57 | 58 | public long getTimestamp() { 59 | return timestamp; 60 | } 61 | 62 | public void setTimestamp(long timestamp) { 63 | this.timestamp = timestamp; 64 | } 65 | 66 | public String getTimeString() { 67 | return format.format(new Date(timestamp)); 68 | } 69 | 70 | public void setPrice(String price) { 71 | this.price = price; 72 | } 73 | 74 | @Override 75 | public String toString() { 76 | return "Quote [time=" + getTimeString() + ", stock=" + stock + ", price=" + price + "]"; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/domain/Stock.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.domain; 18 | 19 | /** 20 | * @author Mark Fisher 21 | * @author Dave Syer 22 | */ 23 | public class Stock { 24 | 25 | private String ticker; 26 | 27 | private StockExchange stockExchange; 28 | 29 | // For de-seialization: 30 | public Stock() { 31 | } 32 | 33 | public Stock(StockExchange stockExchange, String ticker) { 34 | this.stockExchange = stockExchange; 35 | this.ticker = ticker; 36 | } 37 | 38 | public String getTicker() { 39 | return ticker; 40 | } 41 | 42 | public StockExchange getStockExchange() { 43 | return stockExchange; 44 | } 45 | 46 | public void setTicker(String ticker) { 47 | this.ticker = ticker; 48 | } 49 | 50 | public void setStockExchange(StockExchange stockExchange) { 51 | this.stockExchange = stockExchange; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Stock [ticker=" + ticker + ", stockExchange=" + stockExchange + "]"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/domain/StockExchange.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.domain; 18 | 19 | /** 20 | * Enumeration for Stock Exchanges. 21 | * 22 | * @author Mark Fisher 23 | */ 24 | public enum StockExchange { 25 | 26 | nyse, nasdaq; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/domain/TradeRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.domain; 17 | 18 | import java.math.BigDecimal; 19 | import java.util.UUID; 20 | 21 | /** 22 | * Simple trade request 'data' object. No functionality in this 'domain' class. 23 | * @author Mark Pollack 24 | * 25 | */ 26 | public class TradeRequest { 27 | 28 | private String ticker; 29 | 30 | private long quantity; 31 | 32 | private BigDecimal price; 33 | 34 | private String orderType; 35 | 36 | private String accountName; 37 | 38 | private boolean buyRequest; 39 | 40 | private String userName; 41 | 42 | private String requestId; 43 | 44 | private String id = UUID.randomUUID().toString(); 45 | 46 | public String getTicker() { 47 | return ticker; 48 | } 49 | 50 | public void setTicker(String ticker) { 51 | this.ticker = ticker; 52 | } 53 | 54 | public long getQuantity() { 55 | return quantity; 56 | } 57 | 58 | public void setQuantity(long quantity) { 59 | this.quantity = quantity; 60 | } 61 | 62 | public BigDecimal getPrice() { 63 | return price; 64 | } 65 | 66 | public void setPrice(BigDecimal price) { 67 | this.price = price; 68 | } 69 | 70 | public String getOrderType() { 71 | return orderType; 72 | } 73 | 74 | public void setOrderType(String orderType) { 75 | this.orderType = orderType; 76 | } 77 | 78 | public String getAccountName() { 79 | return accountName; 80 | } 81 | 82 | public void setAccountName(String accountName) { 83 | this.accountName = accountName; 84 | } 85 | 86 | public boolean isBuyRequest() { 87 | return buyRequest; 88 | } 89 | 90 | public void setBuyRequest(boolean buyRequest) { 91 | this.buyRequest = buyRequest; 92 | } 93 | 94 | public String getUserName() { 95 | return userName; 96 | } 97 | 98 | public void setUserName(String userName) { 99 | this.userName = userName; 100 | } 101 | 102 | public String getRequestId() { 103 | return requestId; 104 | } 105 | 106 | public void setRequestId(String requestId) { 107 | this.requestId = requestId; 108 | } 109 | 110 | public String getId() { 111 | return id; 112 | } 113 | 114 | public void setId(String id) { 115 | this.id = id; 116 | } 117 | 118 | 119 | } 120 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/domain/TradeResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.springframework.amqp.rabbit.stocks.domain; 14 | 15 | import java.math.BigDecimal; 16 | import java.util.Date; 17 | 18 | /** 19 | * Simple trade request 'data' object. No functionality in this 'domain' class. 20 | * @author Mark Pollack 21 | * 22 | */ 23 | public class TradeResponse { 24 | 25 | private String ticker; 26 | 27 | private long quantity; 28 | 29 | private BigDecimal price; 30 | 31 | private String orderType; 32 | 33 | private String confirmationNumber; 34 | 35 | private boolean error; 36 | 37 | private String errorMessage; 38 | 39 | private String accountName; 40 | 41 | private long timestamp = new Date().getTime(); 42 | 43 | private String requestId; 44 | 45 | public String getRequestId() { 46 | return requestId; 47 | } 48 | 49 | public void setRequestId(String requestId) { 50 | this.requestId = requestId; 51 | } 52 | 53 | public String getTicker() { 54 | return ticker; 55 | } 56 | 57 | public void setTicker(String ticker) { 58 | this.ticker = ticker; 59 | } 60 | 61 | public long getQuantity() { 62 | return quantity; 63 | } 64 | 65 | public void setQuantity(long quantity) { 66 | this.quantity = quantity; 67 | } 68 | 69 | public BigDecimal getPrice() { 70 | return price; 71 | } 72 | 73 | public void setPrice(BigDecimal price) { 74 | this.price = price; 75 | } 76 | 77 | public String getOrderType() { 78 | return orderType; 79 | } 80 | 81 | public void setOrderType(String orderType) { 82 | this.orderType = orderType; 83 | } 84 | 85 | public String getConfirmationNumber() { 86 | return confirmationNumber; 87 | } 88 | 89 | public void setConfirmationNumber(String confirmationNumber) { 90 | this.confirmationNumber = confirmationNumber; 91 | } 92 | 93 | public String getAccountName() { 94 | return accountName; 95 | } 96 | 97 | public void setAccountName(String accountName) { 98 | this.accountName = accountName; 99 | } 100 | 101 | public boolean isError() { 102 | return error; 103 | } 104 | 105 | public void setError(boolean error) { 106 | this.error = error; 107 | } 108 | 109 | public String getErrorMessage() { 110 | return errorMessage; 111 | } 112 | 113 | public void setErrorMessage(String errorMessage) { 114 | this.errorMessage = errorMessage; 115 | } 116 | 117 | public long getTimestamp() { 118 | return timestamp; 119 | } 120 | 121 | public void setTimestamp(long timestamp) { 122 | this.timestamp = timestamp; 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return "TradeResponse [accountName=" + accountName + ", requestId=" 128 | + requestId + ", confirmationNumber=" + confirmationNumber 129 | + ", error=" + error + ", errorMessage=" + errorMessage 130 | + ", orderType=" + orderType + ", price=" + price 131 | + ", quantity=" + quantity + ", ticker=" + ticker + "]"; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/gateway/MarketDataGateway.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.gateway; 17 | 18 | /** 19 | * Gateway interface for sending market data to clients 20 | * @author Mark Pollack 21 | * 22 | */ 23 | public interface MarketDataGateway { 24 | 25 | void sendMarketData(); 26 | } 27 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/gateway/RabbitMarketDataGateway.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.gateway; 18 | 19 | import java.text.DecimalFormat; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Random; 23 | 24 | import org.apache.commons.logging.Log; 25 | import org.apache.commons.logging.LogFactory; 26 | 27 | import org.springframework.amqp.rabbit.core.RabbitGatewaySupport; 28 | import org.springframework.amqp.rabbit.stocks.domain.Quote; 29 | import org.springframework.amqp.rabbit.stocks.domain.Stock; 30 | import org.springframework.amqp.rabbit.stocks.domain.StockExchange; 31 | 32 | /** 33 | * Rabbit implementation of the {@link MarketDataGateway} for sending Market data. 34 | * 35 | * @author Mark Pollack 36 | * @author Mark Fisher 37 | * @author Gary Russell 38 | */ 39 | public class RabbitMarketDataGateway extends RabbitGatewaySupport implements MarketDataGateway { 40 | 41 | private static Log logger = LogFactory.getLog(RabbitMarketDataGateway.class); 42 | 43 | private static final Random random = new Random(); 44 | 45 | private final List stocks = new ArrayList(); 46 | 47 | 48 | public RabbitMarketDataGateway() { 49 | this.stocks.add(new MockStock("AAPL", StockExchange.nasdaq, 255)); 50 | this.stocks.add(new MockStock("CSCO", StockExchange.nasdaq, 22)); 51 | this.stocks.add(new MockStock("DELL", StockExchange.nasdaq, 15)); 52 | this.stocks.add(new MockStock("GOOG", StockExchange.nasdaq, 500)); 53 | this.stocks.add(new MockStock("INTC", StockExchange.nasdaq, 22)); 54 | this.stocks.add(new MockStock("MSFT", StockExchange.nasdaq, 29)); 55 | this.stocks.add(new MockStock("ORCL", StockExchange.nasdaq, 24)); 56 | this.stocks.add(new MockStock("CAJ", StockExchange.nyse, 43)); 57 | this.stocks.add(new MockStock("F", StockExchange.nyse, 12)); 58 | this.stocks.add(new MockStock("GE", StockExchange.nyse, 18)); 59 | this.stocks.add(new MockStock("HMC", StockExchange.nyse, 32)); 60 | this.stocks.add(new MockStock("HPQ", StockExchange.nyse, 48)); 61 | this.stocks.add(new MockStock("IBM", StockExchange.nyse, 130)); 62 | this.stocks.add(new MockStock("TM", StockExchange.nyse, 76)); 63 | } 64 | 65 | 66 | public void sendMarketData() { 67 | Quote quote = generateFakeQuote(); 68 | Stock stock = quote.getStock(); 69 | logger.info("Sending Market Data for " + stock.getTicker()); 70 | String routingKey = "app.stock.quotes."+ stock.getStockExchange() + "." + stock.getTicker(); 71 | getRabbitOperations().convertAndSend(routingKey, quote); 72 | } 73 | 74 | private Quote generateFakeQuote() { 75 | MockStock stock = this.stocks.get(random.nextInt(this.stocks.size())); 76 | String price = stock.randomPrice(); 77 | return new Quote(stock, price); 78 | } 79 | 80 | 81 | private static class MockStock extends Stock { 82 | 83 | private final int basePrice; 84 | private final DecimalFormat twoPlacesFormat = new DecimalFormat("0.00"); 85 | 86 | private MockStock(String ticker, StockExchange stockExchange, int basePrice) { 87 | super(stockExchange, ticker); 88 | this.basePrice = basePrice; 89 | } 90 | 91 | private String randomPrice() { 92 | return this.twoPlacesFormat.format(this.basePrice + Math.abs(random.nextGaussian())); 93 | } 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/gateway/RabbitStockServiceGateway.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2018 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.gateway; 18 | 19 | import java.util.UUID; 20 | 21 | import org.springframework.amqp.AmqpException; 22 | import org.springframework.amqp.core.Message; 23 | import org.springframework.amqp.core.MessagePostProcessor; 24 | import org.springframework.amqp.rabbit.core.RabbitGatewaySupport; 25 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 26 | 27 | /** 28 | * Rabbit implementation of {@link StockServiceGateway} to send trade requests to an external process. 29 | * 30 | * @author Mark Pollack 31 | * @author Gary Russell 32 | */ 33 | public class RabbitStockServiceGateway extends RabbitGatewaySupport implements StockServiceGateway { 34 | 35 | private String defaultReplyTo; 36 | 37 | public void setDefaultReplyTo(String defaultReplyTo) { 38 | this.defaultReplyTo = defaultReplyTo; 39 | } 40 | 41 | public void send(TradeRequest tradeRequest) { 42 | getRabbitOperations().convertAndSend(tradeRequest, new MessagePostProcessor() { 43 | public Message postProcessMessage(Message message) throws AmqpException { 44 | message.getMessageProperties().setReplyTo(defaultReplyTo); 45 | message.getMessageProperties().setCorrelationId(UUID.randomUUID().toString()); 46 | return message; 47 | } 48 | }); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/gateway/StockServiceGateway.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.gateway; 18 | 19 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 20 | 21 | /** 22 | * Gateway interface that sends trades to an external process. 23 | * 24 | * @author Mark Pollack 25 | */ 26 | public interface StockServiceGateway { 27 | 28 | void send(TradeRequest tradeRequest); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/handler/ClientHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.handler; 18 | 19 | import org.apache.commons.logging.Log; 20 | import org.apache.commons.logging.LogFactory; 21 | 22 | import org.springframework.amqp.rabbit.stocks.domain.Quote; 23 | import org.springframework.amqp.rabbit.stocks.domain.Stock; 24 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 25 | import org.springframework.amqp.rabbit.stocks.ui.StockController; 26 | 27 | /** 28 | * POJO handler that receives market data and trade responses. Calls are delegated to the UI controller. 29 | * 30 | * @author Mark Pollack 31 | * @author Mark Fisher 32 | */ 33 | public class ClientHandler { 34 | 35 | private static Log log = LogFactory.getLog(ClientHandler.class); 36 | 37 | private StockController stockController; 38 | 39 | public StockController getStockController() { 40 | return stockController; 41 | } 42 | 43 | public void setStockController(StockController stockController) { 44 | this.stockController = stockController; 45 | } 46 | 47 | public void handleMessage(Quote quote) { 48 | Stock stock = quote.getStock(); 49 | log.info("Received market data. Ticker = " + stock.getTicker() + ", Price = " + quote.getPrice()); 50 | stockController.displayQuote(quote); 51 | } 52 | 53 | public void handleMessage(TradeResponse tradeResponse) { 54 | log.info("Received trade repsonse. [" + tradeResponse + "]"); 55 | stockController.updateTrade(tradeResponse); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/handler/ServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.handler; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 22 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 23 | import org.springframework.amqp.rabbit.stocks.service.CreditCheckService; 24 | import org.springframework.amqp.rabbit.stocks.service.ExecutionVenueService; 25 | import org.springframework.amqp.rabbit.stocks.service.TradingService; 26 | import org.springframework.util.StringUtils; 27 | 28 | 29 | /** 30 | * POJO handler that receives trade requests and sends back a trade response. Main application 31 | * logic sits here which coordinates between {@link ExecutionVenueService}, {@link CreditCheckService}, 32 | * and {@link TradingService}. 33 | * 34 | * @author Mark Pollack 35 | * 36 | */ 37 | public class ServerHandler { 38 | 39 | private ExecutionVenueService executionVenueService; 40 | 41 | private CreditCheckService creditCheckService; 42 | 43 | private TradingService tradingService; 44 | 45 | 46 | 47 | public ServerHandler(ExecutionVenueService executionVenueService, 48 | CreditCheckService creditCheckService, 49 | TradingService tradingService) { 50 | this.executionVenueService = executionVenueService; 51 | this.creditCheckService = creditCheckService; 52 | this.tradingService = tradingService; 53 | } 54 | 55 | public TradeResponse handleMessage(TradeRequest tradeRequest) 56 | { 57 | TradeResponse tradeResponse; 58 | List errors = new ArrayList(); 59 | if (creditCheckService.canExecute(tradeRequest, errors)) 60 | { 61 | tradeResponse = executionVenueService.executeTradeRequest(tradeRequest); 62 | } 63 | else 64 | { 65 | tradeResponse = new TradeResponse(); 66 | tradeResponse.setError(true); 67 | tradeResponse.setErrorMessage(StringUtils.arrayToCommaDelimitedString(errors.toArray())); 68 | 69 | } 70 | tradingService.processTrade(tradeRequest, tradeResponse); 71 | return tradeResponse; 72 | } 73 | 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/CreditCheckService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service; 17 | 18 | import java.util.List; 19 | 20 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 21 | 22 | /** 23 | * Credit service to see if the incoming trade can be processed. If it can not be processed 24 | * a false value is returned and the error list contains information as to what went wrong. 25 | * 26 | * @author Mark Pollack 27 | * 28 | */ 29 | public interface CreditCheckService { 30 | 31 | boolean canExecute(TradeRequest tradeRequest, List errors); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/ExecutionVenueService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service; 17 | 18 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 19 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 20 | 21 | /** 22 | * Executes the trade request, creating a Trade response. See the 23 | * code flow in {@link org.springframework.amqp.rabbit.stocks.handler.ServerHandler} 24 | * for its usage. 25 | * 26 | * @author Mark Pollack 27 | */ 28 | public interface ExecutionVenueService { 29 | 30 | TradeResponse executeTradeRequest(TradeRequest request); 31 | } 32 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/TradingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service; 17 | 18 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 19 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 20 | 21 | /** 22 | * Trading Service to process trade requests and response. This is the place to perform 23 | * any trade processing after executions. See code flow in 24 | * {@link org.springframework.amqp.rabbit.stocks.handler.ServerHandler} 25 | * 26 | * @author Mark Pollack 27 | */ 28 | public interface TradingService { 29 | 30 | void processTrade(TradeRequest request, TradeResponse response); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/stubs/CreditCheckServiceStub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service.stubs; 17 | 18 | import java.util.List; 19 | 20 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 21 | import org.springframework.amqp.rabbit.stocks.service.CreditCheckService; 22 | 23 | /*** 24 | * An implementation that always returns true (just like real-life for a mortgage check :) 25 | * 26 | * @author Mark Pollack 27 | * 28 | */ 29 | public class CreditCheckServiceStub implements CreditCheckService { 30 | 31 | public boolean canExecute(TradeRequest tradeRequest, List errors) { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/stubs/ExecutionVenueServiceStub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service.stubs; 17 | 18 | import java.math.BigDecimal; 19 | import java.util.Random; 20 | import java.util.UUID; 21 | 22 | import org.apache.commons.logging.Log; 23 | import org.apache.commons.logging.LogFactory; 24 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 25 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 26 | import org.springframework.amqp.rabbit.stocks.service.ExecutionVenueService; 27 | 28 | /** 29 | * Execute the trade, setting the execution price to changing value in line with what the market data feed is producing. 30 | * 31 | * @author Mark Pollack 32 | * 33 | */ 34 | public class ExecutionVenueServiceStub implements ExecutionVenueService { 35 | 36 | private static Log log = LogFactory.getLog(ExecutionVenueServiceStub.class); 37 | 38 | private Random random = new Random(); 39 | 40 | public TradeResponse executeTradeRequest(TradeRequest request) { 41 | TradeResponse response = new TradeResponse(); 42 | response.setAccountName(request.getAccountName()); 43 | response.setOrderType(request.getOrderType()); 44 | response.setPrice(calculatePrice(request.getTicker(), request.getQuantity(), request.getOrderType(), request.getPrice(), request.getUserName())); 45 | response.setQuantity(request.getQuantity()); 46 | response.setTicker(request.getTicker()); 47 | response.setRequestId(request.getId()); 48 | response.setConfirmationNumber(UUID.randomUUID().toString()); 49 | 50 | 51 | try { 52 | log.info("Sleeping 2 seconds to simulate processing.."); 53 | Thread.sleep(2000); 54 | } catch (InterruptedException e) { 55 | log.error("Didn't finish sleeping", e); 56 | } 57 | return response; 58 | } 59 | 60 | private BigDecimal calculatePrice(String ticker, long quantity, 61 | String orderType, BigDecimal price, String userName) { 62 | // provide as sophisticated implementation...for now all the same price. 63 | if (orderType.compareTo("LIMIT") == 0) 64 | { 65 | return price; 66 | } 67 | else 68 | { 69 | //in line with market data implementation 70 | return new BigDecimal(22 + Math.abs(gaussian())); 71 | } 72 | } 73 | 74 | private double gaussian() { 75 | return random.nextGaussian(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/service/stubs/TradingServiceStub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.amqp.rabbit.stocks.service.stubs; 17 | 18 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 19 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 20 | import org.springframework.amqp.rabbit.stocks.service.TradingService; 21 | 22 | /** 23 | * No-op implementation 24 | * @author Mark Pollack 25 | * 26 | */ 27 | public class TradingServiceStub implements TradingService { 28 | 29 | public void processTrade(TradeRequest request, TradeResponse response) { 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/ui/StockController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.ui; 18 | 19 | import org.springframework.amqp.rabbit.stocks.domain.Quote; 20 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 21 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 22 | import org.springframework.amqp.rabbit.stocks.gateway.StockServiceGateway; 23 | 24 | /** 25 | * Basic controller for the UI. 26 | * TODO: Fix that the UI can receive events before it's panel has been initialized. 27 | * 28 | * @author Mark Pollack 29 | * @author Mark Fisher 30 | */ 31 | public class StockController { 32 | 33 | private StockPanel stockPanel; 34 | 35 | private StockServiceGateway stockServiceGateway; 36 | 37 | 38 | public StockPanel getStockPanel() { 39 | return stockPanel; 40 | } 41 | 42 | public void setStockPanel(StockPanel stockPanel) { 43 | this.stockPanel = stockPanel; 44 | } 45 | 46 | public StockServiceGateway getStockServiceGateway() { 47 | return stockServiceGateway; 48 | } 49 | 50 | public void setStockServiceGateway(StockServiceGateway stockServiceGateway) { 51 | this.stockServiceGateway = stockServiceGateway; 52 | } 53 | 54 | // "Actions" 55 | 56 | public void sendTradeRequest(String text) { 57 | String[] tokens = text.split("\\s"); 58 | String quantityString = tokens[0]; 59 | String ticker = tokens[1]; 60 | int quantity = Integer.parseInt(quantityString); 61 | TradeRequest tr = new TradeRequest(); 62 | tr.setAccountName("ACCT-123"); 63 | tr.setBuyRequest(true); 64 | tr.setOrderType("MARKET"); 65 | tr.setTicker(ticker); 66 | tr.setQuantity(quantity); 67 | tr.setRequestId("REQ-1"); 68 | tr.setUserName("Joe Trader"); 69 | tr.setUserName("Joe"); 70 | stockServiceGateway.send(tr); 71 | } 72 | 73 | public void displayQuote(Quote quote) { 74 | //TODO race condition with message delivery and initialization... use @Configurable? 75 | if (stockPanel != null) { 76 | stockPanel.displayQuote(quote); 77 | } 78 | } 79 | 80 | public void updateTrade(TradeResponse tradeResponse) { 81 | stockPanel.update(tradeResponse); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/ui/StockPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks.ui; 18 | 19 | import java.awt.Color; 20 | import java.awt.event.ActionEvent; 21 | import java.awt.event.ActionListener; 22 | import java.awt.event.FocusEvent; 23 | import java.awt.event.FocusListener; 24 | import java.text.DecimalFormat; 25 | 26 | import javax.swing.BorderFactory; 27 | import javax.swing.JButton; 28 | import javax.swing.JFrame; 29 | import javax.swing.JLabel; 30 | import javax.swing.JPanel; 31 | import javax.swing.JScrollPane; 32 | import javax.swing.JTextArea; 33 | import javax.swing.JTextField; 34 | import javax.swing.SwingUtilities; 35 | 36 | import org.apache.commons.logging.Log; 37 | import org.apache.commons.logging.LogFactory; 38 | 39 | import org.springframework.amqp.rabbit.stocks.domain.Quote; 40 | import org.springframework.amqp.rabbit.stocks.domain.Stock; 41 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 42 | import org.springframework.context.ConfigurableApplicationContext; 43 | import org.springframework.context.support.ClassPathXmlApplicationContext; 44 | 45 | import com.jgoodies.forms.layout.CellConstraints; 46 | import com.jgoodies.forms.layout.FormLayout; 47 | 48 | /** 49 | * A typical poor mans UI to drive the application. 50 | * 51 | * @author Mark Pollack 52 | * @author Mark Fisher 53 | */ 54 | @SuppressWarnings("serial") 55 | public class StockPanel extends JPanel { 56 | 57 | private static Log log = LogFactory.getLog(StockPanel.class); 58 | 59 | private JTextField tradeRequestTextField; 60 | private JButton tradeRequestButton; 61 | private JTextArea marketDataTextArea; 62 | private StockController stockController; 63 | 64 | private DecimalFormat frmt = new DecimalFormat("$0.00"); 65 | 66 | public StockPanel(StockController controller) { 67 | this.stockController = controller; 68 | controller.setStockPanel(this); 69 | this.setBorder(BorderFactory.createTitledBorder("Stock Form")); 70 | 71 | FormLayout formLayout = new FormLayout("pref, 150dlu", // columns 72 | "pref, fill:100dlu:grow"); // rows 73 | setLayout(formLayout); 74 | CellConstraints c = new CellConstraints(); 75 | 76 | tradeRequestButton = new JButton("Send Trade Request"); 77 | add(tradeRequestButton, c.xy(1, 1)); 78 | 79 | tradeRequestTextField = new JTextField(""); 80 | add(tradeRequestTextField, c.xy(2, 1)); 81 | 82 | add(new JLabel("Market Data"), c.xy(1, 2)); 83 | 84 | marketDataTextArea = new JTextArea(); 85 | JScrollPane sp = new JScrollPane(marketDataTextArea); 86 | sp.setSize(200, 300); 87 | 88 | add(sp, c.xy(2, 2)); 89 | 90 | tradeRequestTextField.addFocusListener(new FocusListener() { 91 | public void focusLost(FocusEvent e) { 92 | } 93 | public void focusGained(FocusEvent e) { 94 | tradeRequestTextField.setText(""); 95 | tradeRequestTextField.setForeground(Color.BLACK); 96 | } 97 | }); 98 | 99 | tradeRequestButton.addActionListener(new ActionListener() { 100 | public void actionPerformed(ActionEvent e) { 101 | sendTradeRequest(); 102 | } 103 | }); 104 | } 105 | 106 | private void sendTradeRequest() { 107 | try { 108 | stockController.sendTradeRequest(tradeRequestTextField.getText()); 109 | tradeRequestTextField.setForeground(Color.GRAY); 110 | tradeRequestTextField.setText("Request Pending..."); 111 | log.info("Sent trade request."); 112 | } 113 | catch (Exception ex) { 114 | tradeRequestTextField.setForeground(Color.RED); 115 | tradeRequestTextField.setText("Required Format: 100 TCKR"); 116 | } 117 | } 118 | 119 | public static void main(String[] a) { 120 | ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("client-bootstrap-config.xml"); 121 | StockController controller = context.getBean(StockController.class); 122 | JFrame f = new JFrame("Rabbit Stock Demo"); 123 | f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 124 | //TODO consider @Configurable 125 | f.add(new StockPanel(controller)); 126 | f.pack(); 127 | f.setVisible(true); 128 | } 129 | 130 | public void displayQuote(final Quote quote) { 131 | SwingUtilities.invokeLater(new Runnable() { 132 | public void run() { 133 | Stock stock = quote.getStock(); 134 | marketDataTextArea.append(stock.getTicker() + " " + quote.getPrice() + "\n"); 135 | } 136 | }); 137 | } 138 | 139 | public void update(final TradeResponse tradeResponse) { 140 | SwingUtilities.invokeLater(new Runnable() { 141 | public void run() { 142 | tradeRequestTextField.setForeground(Color.GREEN); 143 | tradeRequestTextField.setText("Confirmed. " 144 | + tradeResponse.getTicker() + " " 145 | + frmt.format(tradeResponse.getPrice().doubleValue())); 146 | } 147 | }); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /stocks/src/main/java/org/springframework/amqp/rabbit/stocks/web/QuoteController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.springframework.amqp.rabbit.stocks.web; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | import java.util.Collections; 18 | import java.util.Comparator; 19 | import java.util.Iterator; 20 | import java.util.List; 21 | import java.util.Queue; 22 | import java.util.concurrent.ConcurrentHashMap; 23 | import java.util.concurrent.ConcurrentMap; 24 | import java.util.concurrent.PriorityBlockingQueue; 25 | 26 | import org.apache.commons.logging.Log; 27 | import org.apache.commons.logging.LogFactory; 28 | import org.springframework.amqp.rabbit.stocks.domain.Quote; 29 | import org.springframework.amqp.rabbit.stocks.domain.TradeRequest; 30 | import org.springframework.amqp.rabbit.stocks.domain.TradeResponse; 31 | import org.springframework.amqp.rabbit.stocks.gateway.StockServiceGateway; 32 | import org.springframework.stereotype.Controller; 33 | import org.springframework.util.StringUtils; 34 | import org.springframework.web.bind.annotation.ModelAttribute; 35 | import org.springframework.web.bind.annotation.RequestMapping; 36 | import org.springframework.web.bind.annotation.RequestMethod; 37 | import org.springframework.web.bind.annotation.RequestParam; 38 | import org.springframework.web.bind.annotation.ResponseBody; 39 | 40 | /** 41 | * @author Dave Syer 42 | * 43 | */ 44 | @Controller 45 | public class QuoteController { 46 | 47 | private static Log logger = LogFactory.getLog(QuoteController.class); 48 | 49 | private StockServiceGateway stockServiceGateway; 50 | 51 | private ConcurrentMap responses = new ConcurrentHashMap(); 52 | 53 | private Queue quotes = new PriorityBlockingQueue(100, new QuoteComparator()); 54 | 55 | private long timeout = 30000; // 30 seconds of data 56 | 57 | public void setStockServiceGateway(StockServiceGateway stockServiceGateway) { 58 | this.stockServiceGateway = stockServiceGateway; 59 | } 60 | 61 | public void handleTrade(TradeResponse response) { 62 | logger.info("Client received: " + response); 63 | String key = response.getRequestId(); 64 | responses.putIfAbsent(key, response); 65 | Collection queue = new ArrayList(responses.values()); 66 | long timestamp = System.currentTimeMillis() - timeout; 67 | for (Iterator iterator = queue.iterator(); iterator.hasNext();) { 68 | TradeResponse tradeResponse = iterator.next(); 69 | if (tradeResponse.getTimestamp() < timestamp) { 70 | responses.remove(tradeResponse.getRequestId()); 71 | } 72 | } 73 | } 74 | 75 | public void handleQuote(Quote message) { 76 | logger.info("Client received: " + message); 77 | long timestamp = System.currentTimeMillis() - timeout; 78 | for (Iterator iterator = quotes.iterator(); iterator.hasNext();) { 79 | Quote quote = iterator.next(); 80 | if (quote.getTimestamp() < timestamp) { 81 | iterator.remove(); 82 | } 83 | } 84 | quotes.add(message); 85 | } 86 | 87 | @RequestMapping("/quotes") 88 | @ResponseBody 89 | public List quotes(@RequestParam(required = false) Long timestamp) { 90 | if (timestamp == null) { 91 | timestamp = 0L; 92 | } 93 | ArrayList list = new ArrayList(); 94 | for (Quote quote : quotes) { 95 | if (quote.getTimestamp() > timestamp) { 96 | list.add(quote); 97 | } 98 | } 99 | Collections.reverse(list); 100 | return list; 101 | } 102 | 103 | @RequestMapping(value = "/trade", method = RequestMethod.POST) 104 | @ResponseBody 105 | public TradeRequest trade(@ModelAttribute TradeRequest tradeRequest) { 106 | String ticker = tradeRequest.getTicker(); 107 | Long quantity = tradeRequest.getQuantity(); 108 | if (quantity == null || quantity <= 0 || !StringUtils.hasText(ticker)) { 109 | // error 110 | return tradeRequest; 111 | } else { 112 | // Fake rest of request while UI is basic 113 | tradeRequest.setAccountName("ACCT-123"); 114 | tradeRequest.setBuyRequest(true); 115 | tradeRequest.setOrderType("MARKET"); 116 | tradeRequest.setRequestId("REQ-1"); 117 | tradeRequest.setUserName("Joe Trader"); 118 | tradeRequest.setUserName("Joe"); 119 | stockServiceGateway.send(tradeRequest); 120 | } 121 | return tradeRequest; 122 | } 123 | 124 | @RequestMapping(value = "/trade", method = RequestMethod.GET) 125 | @ResponseBody 126 | public TradeResponse response(@RequestParam String requestId) { 127 | TradeResponse result = responses.get(requestId); 128 | return result; 129 | } 130 | 131 | private static class QuoteComparator implements Comparator { 132 | 133 | public int compare(Quote o1, Quote o2) { 134 | return new Long(o1.getTimestamp() - o2.getTimestamp()).intValue(); 135 | } 136 | 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /stocks/src/main/resources/client-bootstrap-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /stocks/src/main/resources/client-handlers.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /stocks/src/main/resources/client-messaging.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /stocks/src/main/resources/client.properties: -------------------------------------------------------------------------------- 1 | stocks.quote.pattern=app.stock.quotes.nasdaq.* -------------------------------------------------------------------------------- /stocks/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /stocks/src/main/resources/server-bootstrap-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /stocks/src/main/resources/server-handlers.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /stocks/src/main/resources/server-jmx.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /stocks/src/main/resources/server-messaging.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /stocks/src/main/resources/server-services.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 9 | 10 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /stocks/src/main/resources/servlet-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /stocks/src/main/resources/static/css/colors.css: -------------------------------------------------------------------------------- 1 | /* colors.css 2008/04/22 nicolekonicki */ 2 | 3 | /* 4 | * COLORS CSS 5 | * 6 | * Only css that affects the colors and text decoration of elements 7 | * should be included here. 8 | * 9 | */ 10 | 11 | 12 | /* 13 | * COMMON STYLES 14 | */ 15 | 16 | body 17 | { 18 | background-color: #dfdfdf; 19 | } 20 | 21 | #page 22 | { 23 | color: #333; 24 | } 25 | 26 | 27 | /* 28 | * HEADER STYLES 29 | */ 30 | 31 | #site-name a, #site-name a:hover 32 | { 33 | color: #fff; 34 | } 35 | 36 | #company-name a 37 | { 38 | color:#fff; 39 | } 40 | 41 | 42 | /* 43 | * TEXT FORMATTING STYLES 44 | */ 45 | 46 | h1 { 47 | color: #007c00; 48 | border-bottom: 1px solid #007c00; 49 | } 50 | 51 | h2 { 52 | color: #333; 53 | } 54 | 55 | h3 { 56 | color: #333; 57 | } 58 | 59 | h4 { 60 | color: #333; 61 | } 62 | 63 | 64 | /* 65 | * LINK STYLES 66 | */ 67 | 68 | a:link, 69 | a:visited 70 | { 71 | color: #333; 72 | text-decoration: underline; 73 | } 74 | 75 | a:hover, 76 | a:focus 77 | { 78 | color: #60aa00; 79 | text-decoration: underline; 80 | } 81 | 82 | a:active, 83 | a.active 84 | { 85 | color: #60aa00; 86 | } 87 | 88 | /* 89 | * MENU STYLES 90 | */ 91 | 92 | #primary-left 93 | { 94 | color: #edf2ce; 95 | } 96 | 97 | #primary-left a, #primary-right a 98 | { 99 | color: #edf2ce; 100 | text-decoration:none; 101 | } 102 | 103 | #primary-left a:hover, #primary-right a:hover 104 | { 105 | color:#fff; 106 | text-decoration: none; 107 | } 108 | 109 | 110 | #secondary-navigation 111 | { 112 | background: #fff; 113 | } 114 | 115 | #secondary-navigation li a 116 | { 117 | color:#595959; 118 | border-bottom:1px solid #e4e3e3; 119 | } 120 | 121 | #secondary-navigation a:hover 122 | { 123 | color: #60aa00; 124 | text-decoration: underline; 125 | } 126 | 127 | #secondary-navigation a.active 128 | { 129 | font-weight: bold; 130 | } 131 | 132 | 133 | /* 134 | * CONTAINER STYLES 135 | */ 136 | 137 | #container 138 | { 139 | background:#fff; 140 | } 141 | 142 | 143 | /* 144 | * TABLE STYLES 145 | */ 146 | 147 | table 148 | { 149 | color:#666; 150 | } 151 | 152 | .bordered-table 153 | { 154 | border:1px solid #b8c885; 155 | } 156 | 157 | th 158 | { 159 | color:#333; 160 | } 161 | 162 | .bordered-table th 163 | { 164 | border-bottom: 1px solid #b8c885; 165 | } 166 | 167 | .sublevel1-odd { 168 | background:#f8faf0; 169 | } 170 | 171 | .sublevel1-even { 172 | background:#fff; 173 | } 174 | 175 | .name-sublevel1-odd { 176 | background:#f8faf0; 177 | } 178 | 179 | .name-sublevel1-even { 180 | background:#fff; 181 | } 182 | 183 | 184 | /* 185 | * FOOTER STYLES 186 | */ 187 | 188 | 189 | #footer-left, #footer-right 190 | { 191 | color: #999; 192 | } 193 | 194 | #footer-left a, #footer-right a 195 | { 196 | color: #999; 197 | text-decoration:none; 198 | } 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /stocks/src/main/resources/static/css/local.css: -------------------------------------------------------------------------------- 1 | 2 | .note { 3 | border: 1px solid #FFDDBB; 4 | color: inherit; 5 | background-color: #FFF5EE; 6 | } 7 | 8 | div.note { 9 | padding: 0.5em; 10 | margin-top: 1.5em; 11 | } 12 | 13 | fieldset { 14 | border-width: 0; 15 | margin: 0; 16 | padding: 0; 17 | } 18 | 19 | .inline-labeles label { 20 | margin-left: 0.5em; 21 | } 22 | 23 | #secondary-navigation ul { 24 | padding-top: 6px; 25 | } 26 | 27 | #exports #export-fragment { 28 | width: 50%; 29 | float: right; 30 | padding-bottom: 22px; 31 | } 32 | 33 | .loading_indicator_parent { 34 | position: relative; 35 | } 36 | 37 | #loading_indicator { 38 | position: absolute; 39 | bottom: 5px; 40 | right: 0; 41 | opacity: 0; 42 | } 43 | 44 | textarea { 45 | display: inline; 46 | width: 40%; 47 | height: 2em; 48 | } 49 | 50 | fieldset > div { 51 | margin-top: 0.5em; 52 | } 53 | 54 | .error { 55 | color: red; 56 | backround-color: inherit; 57 | font-weight: bold; 58 | } 59 | 60 | hr { 61 | height: 1px; 62 | border: 0; 63 | background-color: #007C00; 64 | color: #007C00; 65 | } 66 | 67 | #secondary-navigation { 68 | margin-top: 15px; 69 | } 70 | 71 | #secondary-navigation ul li { 72 | margin-bottom: 5px; 73 | } 74 | 75 | #secondary-navigation ul li li { 76 | margin-bottom: 0; 77 | } 78 | 79 | .scroll { 80 | overflow: auto; 81 | border: 1px solid green; 82 | padding: 3px; 83 | height: 200px; 84 | white-space: pre; 85 | } 86 | 87 | .clear { 88 | clear: both; 89 | } 90 | 91 | input#cancel { 92 | position: absolute; 93 | top: 0; 94 | right: 0; 95 | } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | form > fieldset { 104 | border: 0 105 | padding: 4px; 106 | padding-bottom: 8px; 107 | margin: 0 0 10px; 108 | } 109 | 110 | legend { 111 | margin-bottom: 0.25em; 112 | margin-left: 0.25em; 113 | } 114 | 115 | form, legend { 116 | border: 0; 117 | padding: 0; 118 | margin: 0; 119 | } 120 | 121 | form ol, form ul { 122 | list-style: none; 123 | margin: 0; 124 | padding: 0; 125 | } 126 | 127 | form li { 128 | clear: both; 129 | margin: 0 0 .75em; 130 | padding: 0; 131 | } 132 | 133 | .confirm { 134 | margin-bottom: 0.75em; 135 | } 136 | 137 | label { 138 | display: block; 139 | float: left; 140 | margin-right: 10px; 141 | text-align: right; 142 | width: 120px; 143 | } 144 | 145 | label:after { 146 | content: ':'; 147 | } 148 | 149 | .radio label:after, 150 | .confirm label:after { 151 | content: ''; 152 | } 153 | 154 | .confirm label { 155 | display: block; 156 | float: none; 157 | margin-left: 130px; 158 | text-align: left; 159 | width: inherit; 160 | } 161 | 162 | fieldset.smalltab .confirm label { 163 | margin-left: 35px; 164 | } 165 | 166 | form .control { 167 | float: left; 168 | margin-bottom: 8px; 169 | } 170 | 171 | input[type="text"], 172 | input[type="password"] 173 | { 174 | width: 250px; 175 | } 176 | 177 | fieldset .buttonGroup { 178 | clear: both; 179 | margin-left: 130px; 180 | margin-right: 5px; 181 | cursor: pointer; 182 | position: relative; 183 | } 184 | 185 | fieldset.notab .buttonGroup { 186 | margin-left: 0; 187 | } 188 | 189 | fieldset.smalltab .buttonGroup { 190 | margin-left: 35px; 191 | } 192 | 193 | .buttonGroup button, 194 | .buttonGroup input[type="button"], 195 | .buttonGroup input[type="submit"], 196 | .buttonGroup input[type="reset"] { 197 | margin-right: 5px; 198 | } 199 | -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/ajax-loader.gif -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/delete.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/favicon.ico -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/footer-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/footer-left.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/footer-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/footer-right.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/footer-stretch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/footer-stretch.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/header-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/header-left.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/header-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/header-right.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/header-stretch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/header-stretch.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/help.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/issues.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/issues.gif -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/module-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/module-icon.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/powered-by-spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/powered-by-spring.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/primary-item-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/primary-item-background.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/primary-menu-stretch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/primary-menu-stretch.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/primary-wrapper-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/primary-wrapper-left.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/primary-wrapper-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/primary-wrapper-right.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/springsource_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/springsource_logo.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/table-header-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/table-header-background.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/table-header-bottom-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/table-header-bottom-background.png -------------------------------------------------------------------------------- /stocks/src/main/resources/static/images/table-header-top-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spring-projects/spring-amqp-samples/7fd03cc7253667b41643f5f4370e35c1170e9705/stocks/src/main/resources/static/images/table-header-top-background.png -------------------------------------------------------------------------------- /stocks/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | contextConfigLocation 10 | classpath*:/server-bootstrap-*.xml 11 | 12 | 13 | 14 | org.springframework.web.context.ContextLoaderListener 15 | 16 | 17 | 18 | shallowEtagHeaderFilter 19 | org.springframework.web.filter.ShallowEtagHeaderFilter 20 | 21 | 22 | 23 | hiddenHttpMethodFilter 24 | org.springframework.web.filter.HiddenHttpMethodFilter 25 | 26 | 27 | 28 | shallowEtagHeaderFilter 29 | /* 30 | 31 | 32 | 33 | hiddenHttpMethodFilter 34 | /* 35 | 36 | 37 | 38 | main 39 | org.springframework.web.servlet.DispatcherServlet 40 | 41 | contextConfigLocation 42 | classpath*:/servlet-config.xml 43 | 44 | 1 45 | 46 | 47 | 48 | main 49 | / 50 | 51 | 52 | 53 | index.jsp 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /stocks/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 2 | <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> 3 | 4 | 5 | 6 | Spring AMQP Stocks Demo 7 | 8 | 9 | 10 | 11 | 12 | 124 | 125 | 126 |
127 | 140 | 141 |
142 |
143 | This application is a the "stocks" sample from Spring AMQP. 145 | You can get the source code from the Spring 147 | AMQP Samples project on Github. 148 |

Deal

149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 |
160 |
    161 |
  1. 163 |
  2. 164 |
  3. 166 |
  4. 167 |
  5. 168 |
169 |
170 |
171 | 172 |
173 |

Quotes

174 |
Stopped
175 |
176 | 177 | 178 | 179 |

180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 |
TimeTickerPrice
191 |
192 |
193 |
194 |
195 | 196 | -------------------------------------------------------------------------------- /stocks/src/test/java/org/springframework/amqp/rabbit/stocks/Client.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | 14 | package org.springframework.amqp.rabbit.stocks; 15 | 16 | import javax.swing.JFrame; 17 | 18 | import org.junit.After; 19 | import org.junit.Test; 20 | 21 | import org.springframework.amqp.rabbit.stocks.ui.StockController; 22 | import org.springframework.amqp.rabbit.stocks.ui.StockPanel; 23 | import org.springframework.context.ConfigurableApplicationContext; 24 | import org.springframework.context.support.ClassPathXmlApplicationContext; 25 | 26 | /** 27 | * Main client application, can run as an application or unit test. 28 | * 29 | * @author Mark Pollack 30 | */ 31 | public class Client { 32 | 33 | private ConfigurableApplicationContext context; 34 | 35 | public static void main(String[] args) { 36 | new Client().run(); 37 | } 38 | 39 | @Test 40 | public void run() { 41 | context = new ClassPathXmlApplicationContext("client-bootstrap-config.xml"); 42 | StockController controller = context.getBean(StockController.class); 43 | JFrame f = new JFrame("Rabbit Stock Demo"); 44 | f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 45 | // TODO consider @Configurable 46 | f.add(new StockPanel(controller)); 47 | f.pack(); 48 | f.setVisible(true); 49 | } 50 | 51 | @After 52 | public void close() { 53 | if (context != null) { 54 | context.close(); 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /stocks/src/test/java/org/springframework/amqp/rabbit/stocks/Server.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2010 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.amqp.rabbit.stocks; 18 | 19 | import org.junit.After; 20 | import org.junit.Test; 21 | 22 | import org.springframework.context.support.ClassPathXmlApplicationContext; 23 | 24 | /** 25 | * Server application than can be run as an app or unit test. 26 | * 27 | * @author Mark Pollack 28 | */ 29 | public class Server { 30 | 31 | private ClassPathXmlApplicationContext context; 32 | 33 | public static void main(String[] args) { 34 | new Server().run(); 35 | } 36 | 37 | @After 38 | public void close() { 39 | if (context != null) { 40 | context.close(); 41 | } 42 | } 43 | 44 | @Test 45 | public void run() { 46 | context = new ClassPathXmlApplicationContext("server-bootstrap-config.xml"); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /stocks/src/test/java/org/springframework/amqp/rabbit/stocks/web/ServletConfigurationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.springframework.amqp.rabbit.stocks.web; 14 | 15 | import org.junit.Test; 16 | 17 | import org.springframework.web.context.support.XmlWebApplicationContext; 18 | 19 | /** 20 | * @author Dave Syer 21 | * @author Gary Russell 22 | * 23 | */ 24 | public class ServletConfigurationTests { 25 | 26 | @Test 27 | public void testContext() throws Exception { 28 | 29 | XmlWebApplicationContext parent = new XmlWebApplicationContext(); 30 | parent.setConfigLocation("classpath:/server-bootstrap-config.xml"); 31 | parent.refresh(); 32 | 33 | try { 34 | 35 | XmlWebApplicationContext context = new XmlWebApplicationContext(); 36 | context.setParent(parent); 37 | context.setConfigLocation("classpath:/servlet-config.xml"); 38 | context.close(); 39 | 40 | } finally { 41 | 42 | parent.close(); 43 | 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /stocks/src/test/resources/test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Process this file with mustache (gem install mustache) 3 | "headers" : { 4 | timestamp : 1292408628296, 5 | "id": "f301e4cc-6246-4aab-bcf3-a44263c0946b", 6 | ages: bar 7 | } 8 | more : { 9 | names: [ {name: chris}, {name: mark}, {name: scott} ] 10 | } 11 | --- 12 | {{#more}} 13 | {{#names}} 14 | Hi {{name}}! 15 | {{/names}} 16 | {{/more}} 17 | 18 | --------------------------------------------------------------------------------