├── .gitignore ├── README.md ├── ch02 └── rest-api-demo │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiDemoApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── annotation │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ └── CurrencyCodeAudit.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ └── CurrencyConversionService.java │ └── resources │ │ ├── application.properties │ │ └── public │ │ └── error │ │ ├── 4xx.html │ │ └── 5xx.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiDemoApplicationTests.java ├── ch03 └── rest-api-events │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiEventsApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── annotation │ │ │ ├── Log.java │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ ├── CodeLogger.java │ │ │ ├── CurrencyCodeAudit.java │ │ │ └── CurrencyConversionAudit.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── event │ │ │ ├── CurrencyConversionEvent.java │ │ │ └── CurrencyEvent.java │ │ │ ├── exception │ │ │ └── BadCodeRuntimeException.java │ │ │ ├── listener │ │ │ ├── CurrencyConversionEventListener.java │ │ │ ├── RateEventListener.java │ │ │ ├── RestApiEventsListener.java │ │ │ └── RestAppEventListener.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ ├── CurrencyConversionService.java │ │ │ └── CurrencyService.java │ └── resources │ │ ├── application.properties │ │ └── public │ │ └── error │ │ ├── 4xx.html │ │ └── 5xx.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiEventsApplicationTests.java ├── ch04 ├── jms-sender │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── JmsSenderApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── aop │ │ │ │ └── JMSAudit.java │ │ │ │ ├── config │ │ │ │ ├── JMSConfig.java │ │ │ │ └── JMSProperties.java │ │ │ │ ├── domain │ │ │ │ └── Rate.java │ │ │ │ └── jms │ │ │ │ ├── AnnotatedReceiver.java │ │ │ │ ├── QueueListener.java │ │ │ │ ├── RateReceiver.java │ │ │ │ ├── RateReplyReceiver.java │ │ │ │ ├── RateSender.java │ │ │ │ └── SimpleSender.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── JmsSenderApplicationTests.java ├── jms-topic-subscriber │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── JmsTopicSubscriberApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── aop │ │ │ │ └── JMSAudit.java │ │ │ │ ├── config │ │ │ │ ├── JMSConfig.java │ │ │ │ └── JMSProperties.java │ │ │ │ ├── domain │ │ │ │ └── Rate.java │ │ │ │ └── jms │ │ │ │ └── RateTopicReceiver.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── JmsTopicSubscriberApplicationTests.java └── rest-api-jms │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiJMSApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── annotation │ │ │ ├── Log.java │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ ├── CodeLogger.java │ │ │ ├── CurrencyCodeAudit.java │ │ │ └── CurrencyConversionAudit.java │ │ │ ├── config │ │ │ ├── RateJmsConfiguration.java │ │ │ └── RateProperties.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── event │ │ │ ├── CurrencyConversionEvent.java │ │ │ └── CurrencyEvent.java │ │ │ ├── exception │ │ │ └── BadCodeRuntimeException.java │ │ │ ├── jms │ │ │ └── RateJmsReceiver.java │ │ │ ├── listener │ │ │ ├── CurrencyConversionEventListener.java │ │ │ ├── RateEventListener.java │ │ │ ├── RestApiEventsListener.java │ │ │ └── RestAppEventListener.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ ├── CurrencyConversionService.java │ │ │ └── CurrencyService.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.properties │ │ └── public │ │ └── error │ │ ├── 4xx.html │ │ └── 5xx.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiJMSApplicationTests.java ├── ch05 ├── amqp-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── AmqpDemoApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── amqp │ │ │ │ ├── AnnotatedConsumer.java │ │ │ │ ├── Consumer.java │ │ │ │ ├── MultiListenerService.java │ │ │ │ ├── Producer.java │ │ │ │ ├── RateConsumer.java │ │ │ │ ├── RateProducer.java │ │ │ │ ├── ReplyToService.java │ │ │ │ ├── RpcClient.java │ │ │ │ └── RpcServer.java │ │ │ │ ├── aop │ │ │ │ └── AMQPAudit.java │ │ │ │ ├── config │ │ │ │ ├── AMQPConfig.java │ │ │ │ └── AMQPProperties.java │ │ │ │ ├── domain │ │ │ │ ├── ClientRate.java │ │ │ │ ├── Invoice.java │ │ │ │ ├── InvoiceWithTax.java │ │ │ │ ├── Item.java │ │ │ │ ├── Order.java │ │ │ │ └── Rate.java │ │ │ │ └── listener │ │ │ │ └── RabbitMQEventListener.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── AmqpDemoApplicationTests.java └── rest-api-amqp │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiAMQPApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── amqp │ │ │ ├── RateConsumer.java │ │ │ └── RateProducer.java │ │ │ ├── annotation │ │ │ ├── Log.java │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ ├── CodeLogger.java │ │ │ ├── CurrencyCodeAudit.java │ │ │ └── CurrencyConversionAudit.java │ │ │ ├── config │ │ │ ├── RateJmsConfiguration.java │ │ │ └── RateProperties.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── event │ │ │ ├── CurrencyConversionEvent.java │ │ │ └── CurrencyEvent.java │ │ │ ├── exception │ │ │ └── BadCodeRuntimeException.java │ │ │ ├── jms │ │ │ └── RateJmsReceiver.java │ │ │ ├── listener │ │ │ ├── CurrencyConversionEventListener.java │ │ │ ├── RateEventListener.java │ │ │ ├── RestApiEventsListener.java │ │ │ └── RestAppEventListener.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ ├── CurrencyConversionService.java │ │ │ └── CurrencyService.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.properties │ │ └── public │ │ └── error │ │ ├── 4xx.html │ │ └── 5xx.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiAMQPApplicationTests.java ├── ch06 ├── redis-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── RedisDemoApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── aop │ │ │ │ └── RedisAudit.java │ │ │ │ ├── config │ │ │ │ ├── RedisConfig.java │ │ │ │ └── SimpleRedisProperties.java │ │ │ │ ├── domain │ │ │ │ └── Rate.java │ │ │ │ └── redis │ │ │ │ ├── RateSubscriber.java │ │ │ │ └── Subscriber.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── RedisDemoApplicationTests.java └── rest-api-redis │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiAMQPApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── amqp │ │ │ ├── RateConsumer.java │ │ │ └── RateProducer.java │ │ │ ├── annotation │ │ │ ├── Log.java │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ ├── CodeLogger.java │ │ │ ├── CurrencyCodeAudit.java │ │ │ └── CurrencyConversionAudit.java │ │ │ ├── config │ │ │ ├── RateJmsConfiguration.java │ │ │ ├── RateProperties.java │ │ │ ├── RateRedisConfig.java │ │ │ └── RateRedisProperties.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── event │ │ │ ├── CurrencyConversionEvent.java │ │ │ └── CurrencyEvent.java │ │ │ ├── exception │ │ │ └── BadCodeRuntimeException.java │ │ │ ├── jms │ │ │ └── RateJmsReceiver.java │ │ │ ├── listener │ │ │ ├── CurrencyConversionEventListener.java │ │ │ ├── RateEventListener.java │ │ │ ├── RestApiEventsListener.java │ │ │ └── RestAppEventListener.java │ │ │ ├── redis │ │ │ └── RateRedisSubscriber.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ ├── CurrencyConversionService.java │ │ │ └── CurrencyService.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.properties │ │ └── public │ │ └── error │ │ ├── 4xx.html │ │ └── 5xx.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiAMQPApplicationTests.java ├── ch07 ├── rest-api-websockets │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── RestApiWebSocketsApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── amqp │ │ │ │ ├── RateConsumer.java │ │ │ │ └── RateProducer.java │ │ │ │ ├── annotation │ │ │ │ ├── Log.java │ │ │ │ └── ToUpper.java │ │ │ │ ├── aop │ │ │ │ ├── CodeLogger.java │ │ │ │ ├── CurrencyCodeAudit.java │ │ │ │ └── CurrencyConversionAudit.java │ │ │ │ ├── config │ │ │ │ ├── RateJmsConfiguration.java │ │ │ │ ├── RateProperties.java │ │ │ │ ├── RateRedisConfig.java │ │ │ │ ├── RateRedisProperties.java │ │ │ │ ├── RateWebSocketsConfig.java │ │ │ │ └── RateWebSocketsProperties.java │ │ │ │ ├── controller │ │ │ │ └── CurrencyController.java │ │ │ │ ├── domain │ │ │ │ ├── CurrencyConversion.java │ │ │ │ ├── CurrencyExchange.java │ │ │ │ └── Rate.java │ │ │ │ ├── event │ │ │ │ ├── CurrencyConversionEvent.java │ │ │ │ └── CurrencyEvent.java │ │ │ │ ├── exception │ │ │ │ └── BadCodeRuntimeException.java │ │ │ │ ├── jms │ │ │ │ └── RateJmsReceiver.java │ │ │ │ ├── listener │ │ │ │ ├── CurrencyConversionEventListener.java │ │ │ │ ├── RateEventListener.java │ │ │ │ ├── RestApiEventsListener.java │ │ │ │ └── RestAppEventListener.java │ │ │ │ ├── redis │ │ │ │ └── RateRedisSubscriber.java │ │ │ │ ├── repository │ │ │ │ └── RateRepository.java │ │ │ │ └── service │ │ │ │ ├── CurrencyConversionService.java │ │ │ │ └── CurrencyService.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ ├── application.properties │ │ │ └── public │ │ │ ├── error │ │ │ ├── 4xx.html │ │ │ └── 5xx.html │ │ │ └── index-ws.html │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── RestApiWebSocketsApplicationTests.java └── websocket-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── ServletInitializer.java │ │ │ ├── WebSocketsDemoApplication.java │ │ │ ├── aop │ │ │ └── WebSocketsAudit.java │ │ │ ├── config │ │ │ ├── LlWebSocketConfig.java │ │ │ ├── SimpleWebSocketsProperties.java │ │ │ └── WebSocketsConfig.java │ │ │ ├── controller │ │ │ └── SimpleController.java │ │ │ ├── domain │ │ │ ├── ChatMessage.java │ │ │ └── Rate.java │ │ │ └── web │ │ │ └── socket │ │ │ └── LlWebSocketHandler.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.properties │ │ └── static │ │ ├── llws.html │ │ └── sockjs-stomp.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── WebSocketsDemoApplicationTests.java ├── ch08 ├── rest-api-si │ ├── .gitignore │ ├── pom.xml │ ├── rates-2017-02-21.txt │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── RestApiSpiApplication.java │ │ │ │ ├── ServletInitializer.java │ │ │ │ ├── amqp │ │ │ │ ├── RateConsumer.java │ │ │ │ └── RateProducer.java │ │ │ │ ├── annotation │ │ │ │ ├── Log.java │ │ │ │ └── ToUpper.java │ │ │ │ ├── aop │ │ │ │ ├── CodeLogger.java │ │ │ │ ├── CurrencyCodeAudit.java │ │ │ │ └── CurrencyConversionAudit.java │ │ │ │ ├── config │ │ │ │ ├── RateJmsConfiguration.java │ │ │ │ ├── RateProperties.java │ │ │ │ ├── RateRedisConfig.java │ │ │ │ ├── RateRedisProperties.java │ │ │ │ ├── RateSpiConfig.java │ │ │ │ ├── RateSpiProperties.java │ │ │ │ ├── RateWebSocketsConfig.java │ │ │ │ └── RateWebSocketsProperties.java │ │ │ │ ├── controller │ │ │ │ └── CurrencyController.java │ │ │ │ ├── domain │ │ │ │ ├── CurrencyConversion.java │ │ │ │ ├── CurrencyExchange.java │ │ │ │ └── Rate.java │ │ │ │ ├── event │ │ │ │ ├── CurrencyConversionEvent.java │ │ │ │ └── CurrencyEvent.java │ │ │ │ ├── exception │ │ │ │ └── BadCodeRuntimeException.java │ │ │ │ ├── integration │ │ │ │ └── RateServiceActivator.java │ │ │ │ ├── jms │ │ │ │ └── RateJmsReceiver.java │ │ │ │ ├── listener │ │ │ │ ├── CurrencyConversionEventListener.java │ │ │ │ ├── RateEventListener.java │ │ │ │ ├── RestApiEventsListener.java │ │ │ │ └── RestAppEventListener.java │ │ │ │ ├── redis │ │ │ │ └── RateRedisSubscriber.java │ │ │ │ ├── repository │ │ │ │ └── RateRepository.java │ │ │ │ └── service │ │ │ │ ├── CurrencyConversionService.java │ │ │ │ └── CurrencyService.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── additional-spring-configuration-metadata.json │ │ │ ├── application.properties │ │ │ └── public │ │ │ ├── error │ │ │ ├── 4xx.html │ │ │ └── 5xx.html │ │ │ └── index-ws.html │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── RestApiSpiApplicationTests.java └── si-demo │ ├── .gitignore │ ├── contacts.txt │ ├── pom.xml │ ├── rates-2017-02-21.txt │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── SpiDemoApplication.java │ │ │ ├── aop │ │ │ └── SpiAudit.java │ │ │ ├── config │ │ │ ├── RateConfig.java │ │ │ ├── SimpleAnnotationConfiguration.java │ │ │ ├── SpiFileConfiguration.java │ │ │ ├── SpiFileToJdbcConfigutation.java │ │ │ ├── SpiProperties.java │ │ │ └── SpiSimpleConfiguration.java │ │ │ ├── controller │ │ │ └── SimpleController.java │ │ │ ├── domain │ │ │ ├── Person.java │ │ │ └── Rate.java │ │ │ └── integration │ │ │ ├── PersonConverter.java │ │ │ └── SimpleMessageHandler.java │ └── resources │ │ ├── META-INF │ │ └── spring │ │ │ └── integration │ │ │ ├── spi-context.xml │ │ │ └── spi-file-to-jdbc.xml │ │ ├── application.properties │ │ └── schema.sql │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── SpiDemoApplicationTests.java ├── ch09 ├── app-starters │ ├── http │ │ ├── http-source-rabbit-1.1.2.RELEASE.jar │ │ └── start.sh │ └── log │ │ ├── log-sink-rabbit-1.1.1.RELEASE.jar │ │ └── start.sh ├── cloud-stream-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── CloudStreamDemoApplication.java │ │ │ │ ├── aop │ │ │ │ └── CloudStreamAudit.java │ │ │ │ └── cloud │ │ │ │ └── stream │ │ │ │ ├── SimpleProcessor.java │ │ │ │ ├── SimpleSink.java │ │ │ │ └── SimpleSource.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── spring.integration.properties │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── cloud │ │ └── stream │ │ └── CloudStreamDemoApplicationTests.java ├── cloud-stream-processor-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── CloudStreamProcessorDemoApplication.java │ │ │ │ ├── aop │ │ │ │ └── CloudStreamAudit.java │ │ │ │ ├── cloud │ │ │ │ └── stream │ │ │ │ │ └── PersonTicketProcessor.java │ │ │ │ └── domain │ │ │ │ ├── Person.java │ │ │ │ └── Ticket.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messging │ │ └── CloudStreamProcessorDemoApplicationTests.java ├── cloud-stream-sink-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── CloudStreamSinkDemoApplication.java │ │ │ │ ├── aop │ │ │ │ └── CloudStreamAudit.java │ │ │ │ └── cloud │ │ │ │ └── stream │ │ │ │ ├── TicketSink.java │ │ │ │ └── TicketSinkProperties.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messging │ │ └── CloudStreamSinkDemoApplicationTests.java ├── cloud-stream-source-demo │ ├── .gitignore │ ├── contacts.txt │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── CloudStreamSourceDemoApplication.java │ │ │ │ ├── aop │ │ │ │ └── CloudStreamAudit.java │ │ │ │ ├── cloud │ │ │ │ └── stream │ │ │ │ │ ├── PersonFileProperties.java │ │ │ │ │ └── PersonFileSource.java │ │ │ │ ├── domain │ │ │ │ ├── Person.java │ │ │ │ └── Rate.java │ │ │ │ └── integration │ │ │ │ ├── PersonConverter.java │ │ │ │ └── SimpleMessageHandler.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messging │ │ └── CloudStreamSourceDemoApplicationTests.java └── rest-api-cloud-stream │ ├── .gitignore │ ├── output │ └── rates-2017-02-21.processed │ ├── pom.xml │ ├── rates-2017-02-21.txt │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── RestApiCloudStreamApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── amqp │ │ │ ├── RateConsumer.java │ │ │ └── RateProducer.java │ │ │ ├── annotation │ │ │ ├── Log.java │ │ │ └── ToUpper.java │ │ │ ├── aop │ │ │ ├── CodeLogger.java │ │ │ ├── CurrencyCodeAudit.java │ │ │ └── CurrencyConversionAudit.java │ │ │ ├── cloud │ │ │ └── stream │ │ │ │ ├── RateExchange.java │ │ │ │ ├── RateProcessor.java │ │ │ │ └── RateSink.java │ │ │ ├── config │ │ │ ├── RateJmsConfiguration.java │ │ │ ├── RateProperties.java │ │ │ ├── RateRedisConfig.java │ │ │ ├── RateRedisProperties.java │ │ │ ├── RateSpiConfig.java │ │ │ ├── RateSpiProperties.java │ │ │ ├── RateWebSocketsConfig.java │ │ │ └── RateWebSocketsProperties.java │ │ │ ├── controller │ │ │ └── CurrencyController.java │ │ │ ├── domain │ │ │ ├── CurrencyConversion.java │ │ │ ├── CurrencyExchange.java │ │ │ └── Rate.java │ │ │ ├── event │ │ │ ├── CurrencyConversionEvent.java │ │ │ └── CurrencyEvent.java │ │ │ ├── exception │ │ │ └── BadCodeRuntimeException.java │ │ │ ├── integration │ │ │ └── RateServiceActivator.java │ │ │ ├── jms │ │ │ └── RateJmsReceiver.java │ │ │ ├── listener │ │ │ ├── CurrencyConversionEventListener.java │ │ │ ├── RateEventListener.java │ │ │ ├── RestApiEventsListener.java │ │ │ └── RestAppEventListener.java │ │ │ ├── redis │ │ │ └── RateRedisSubscriber.java │ │ │ ├── repository │ │ │ └── RateRepository.java │ │ │ └── service │ │ │ ├── CurrencyConversionService.java │ │ │ └── CurrencyService.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.properties │ │ └── public │ │ ├── error │ │ ├── 4xx.html │ │ └── 5xx.html │ │ └── index-ws.html │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── RestApiCloudStreamApplicationTests.java ├── ch10 ├── reactor-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── ReactorDemoApplication.java │ │ │ │ ├── domain │ │ │ │ └── Exchange.java │ │ │ │ └── service │ │ │ │ └── ExchangeService.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── ReactorDemoApplicationTests.java ├── rxjava-demo │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── RxJavaDemoApplication.java │ │ │ │ ├── domain │ │ │ │ └── Exchange.java │ │ │ │ └── service │ │ │ │ └── ExchangeService.java │ │ └── resources │ │ │ └── application.yaml │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── RxJavaDemoApplicationTests.java ├── spring-web-flux-reactive │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── SpringWebFluxReactiveApplication.java │ │ │ │ ├── config │ │ │ │ └── ReactiveConfig.java │ │ │ │ ├── controller │ │ │ │ └── ReactiveController.java │ │ │ │ ├── domain │ │ │ │ └── Person.java │ │ │ │ └── repository │ │ │ │ └── PersonRepository.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── SpringWebFluxReactiveApplicationTests.java ├── spring-web-flux │ ├── .gitignore │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── apress │ │ │ │ └── messaging │ │ │ │ ├── SpringWebFluxApplication.java │ │ │ │ ├── config │ │ │ │ └── ServerConfig.java │ │ │ │ ├── domain │ │ │ │ └── Person.java │ │ │ │ ├── handler │ │ │ │ └── PersonHandler.java │ │ │ │ └── repository │ │ │ │ └── PersonRepository.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── apress │ │ └── messaging │ │ └── SpringWebFluxApplicationTests.java └── web-emitter │ ├── .gitignore │ ├── pom.xml │ ├── random-names.txt │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ ├── WebEmitterApplication.java │ │ │ ├── config │ │ │ ├── EmitterConfig.java │ │ │ └── EmitterProperties.java │ │ │ └── controller │ │ │ └── SimpleEmitterController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── WebEmitterApplicationTests.java └── ch11 ├── circuit-breaker-service-demo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ └── CircuitBreakerServiceDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── CircuitBreakerServiceDemoApplicationTests.java ├── config-client-demo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ └── ConfigClientDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── ConfigClientDemoApplicationTests.java ├── config-server-demo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ └── ConfigServerDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── ConfigServerDemoApplicationTests.java ├── service-registry-client-demo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ └── ServiceRegistryClientDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── ServiceRegistryClientDemoApplicationTests.java ├── service-registry-server-demo ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apress │ │ │ └── messaging │ │ │ └── ServiceRegistryDemoApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── apress │ └── messaging │ └── ServiceRegistryDemoApplicationTests.java └── service-registry-service-demo ├── .gitignore ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── apress │ │ └── messaging │ │ └── ServiceRegistryServiceDemoApplication.java └── resources │ └── application.properties └── test └── java └── com └── apress └── messaging └── ServiceRegistryServiceDemoApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .DS_Store 3 | 4 | # Mobile Tools for Java (J2ME) 5 | .mtj.tmp/ 6 | 7 | # Package Files # 8 | *.jar 9 | *.war 10 | *.ear 11 | 12 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 13 | hs_err_pid* 14 | 15 | *.pydevproject 16 | .metadata 17 | .gradle 18 | bin/ 19 | tmp/ 20 | *.tmp 21 | *.bak 22 | *.swp 23 | *~.nib 24 | local.properties 25 | .settings/ 26 | .loadpath 27 | .springBeans 28 | build/ 29 | 30 | *.iml 31 | .idea/ 32 | *.ipr 33 | *.iws 34 | /out/ 35 | .idea_modules/ 36 | atlassian-ide-plugin.xml 37 | 38 | RemoteSystemsTempFiles/ 39 | Servers/ 40 | .project 41 | .recommenders 42 | .classpath 43 | mvnw* 44 | .mvn* 45 | */.gitignore 46 | */*.jar 47 | */*.jar.original 48 | target/ 49 | pom.xml.tag 50 | pom.xml.releaseBackup 51 | pom.xml.versionsBackup 52 | pom.xml.next 53 | release.properties 54 | dependency-reduced-pom.xml 55 | buildNumber.properties 56 | .mvn/timing.properties 57 | .factorypath 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring Boot Messaging Book Code from Apress 2 | 3 | ![alt text](https://images.springer.com/sgw/books/medium/9781484212257.jpg "Spring Boot Messaging") 4 | 5 | Spring Boot Messaging 6 | Source Code 7 | 8 | [You can get it here](http://www.apress.com/us/book/9781484212257) 9 | 10 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/RestApiDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | import com.apress.messaging.domain.Rate; 11 | import com.apress.messaging.repository.RateRepository; 12 | 13 | @SpringBootApplication 14 | public class RestApiDemoApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(RestApiDemoApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public CommandLineRunner data(RateRepository repository) { 22 | return (args) -> { 23 | repository.save(new Rate("EUR",0.88857F,new Date())); 24 | repository.save(new Rate("JPY",102.17F,new Date())); 25 | repository.save(new Rate("MXN",19.232F,new Date())); 26 | repository.save(new Rate("GBP",0.75705F,new Date())); 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiDemoApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/domain/CurrencyConversion.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class CurrencyConversion { 4 | 5 | private String base; 6 | private String code; 7 | private float amount; 8 | private float total; 9 | 10 | public CurrencyConversion(){} 11 | 12 | public CurrencyConversion(String base, String code, float amount, float total) { 13 | super(); 14 | this.base = base; 15 | this.code = code; 16 | this.amount = amount; 17 | this.total = total; 18 | } 19 | 20 | public String getBase() { 21 | return base; 22 | } 23 | public void setBase(String base) { 24 | this.base = base; 25 | } 26 | public String getCode() { 27 | return code; 28 | } 29 | public void setCode(String code) { 30 | this.code = code; 31 | } 32 | public float getAmount() { 33 | return amount; 34 | } 35 | public void setAmount(float amount) { 36 | this.amount = amount; 37 | } 38 | public float getTotal() { 39 | return total; 40 | } 41 | public void setTotal(float total) { 42 | this.total = total; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class CurrencyExchange { 4 | 5 | public static final String BASE_CODE = "USD"; 6 | private String base; 7 | private String date; 8 | private Rate[] rates; 9 | 10 | public CurrencyExchange(String base, String date, Rate[] rates) { 11 | super(); 12 | this.base = base; 13 | this.date = date; 14 | this.rates = rates; 15 | } 16 | 17 | public String getBase() { 18 | return base; 19 | } 20 | public void setBase(String base) { 21 | this.base = base; 22 | } 23 | public String getDate() { 24 | return date; 25 | } 26 | public void setDate(String date) { 27 | this.date = date; 28 | } 29 | public Rate[] getRates() { 30 | return rates; 31 | } 32 | public void setRates(Rate[] rates) { 33 | this.rates = rates; 34 | } 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch02/rest-api-demo/src/test/java/com/apress/messaging/RestApiDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/RestApiEventsApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | import com.apress.messaging.domain.Rate; 11 | import com.apress.messaging.service.CurrencyService; 12 | 13 | @SpringBootApplication 14 | public class RestApiEventsApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(RestApiEventsApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public CommandLineRunner data(CurrencyService service) { 22 | return (args) -> { 23 | service.saveRate(new Rate("EUR",0.88857F,new Date())); 24 | service.saveRate(new Rate("JPY",102.17F,new Date())); 25 | service.saveRate(new Rate("MXN",19.232F,new Date())); 26 | service.saveRate(new Rate("GBP",0.75705F,new Date())); 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiEventsApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(String base, String date, Rate[] rates) { 13 | super(); 14 | this.base = base; 15 | this.date = date; 16 | this.rates = rates; 17 | } 18 | 19 | public String getBase() { 20 | return base; 21 | } 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | public String getDate() { 26 | return date; 27 | } 28 | public void setDate(String date) { 29 | this.date = date; 30 | } 31 | public Rate[] getRates() { 32 | return rates; 33 | } 34 | public void setRates(Rate[] rates) { 35 | this.rates = rates; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch03/rest-api-events/src/test/java/com/apress/messaging/RestApiEventsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiEventsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch04/jms-sender/.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/ -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(JmsSenderApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/config/JMSProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="apress.jms") 6 | public class JMSProperties { 7 | 8 | private String queue; 9 | private String rateQueue; 10 | private String rateReplyQueue; 11 | private String topic; 12 | 13 | public String getQueue() { 14 | return queue; 15 | } 16 | public void setQueue(String queue) { 17 | this.queue = queue; 18 | } 19 | public String getRateQueue() { 20 | return rateQueue; 21 | } 22 | public void setRateQueue(String rateQueue) { 23 | this.rateQueue = rateQueue; 24 | } 25 | public String getRateReplyQueue() { 26 | return rateReplyQueue; 27 | } 28 | public void setRateReplyQueue(String rateReplyQueue) { 29 | this.rateReplyQueue = rateReplyQueue; 30 | } 31 | public String getTopic() { 32 | return topic; 33 | } 34 | public void setTopic(String topic) { 35 | this.topic = topic; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/AnnotatedReceiver.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import org.springframework.jms.annotation.JmsListener; 4 | 5 | //@Component 6 | public class AnnotatedReceiver { 7 | 8 | @JmsListener(destination = "${apress.jms.queue}") 9 | public void processMessage(String content) { 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/QueueListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import javax.jms.Message; 4 | import javax.jms.MessageListener; 5 | 6 | //@Component 7 | public class QueueListener implements MessageListener { 8 | 9 | public void onMessage(Message message) { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/RateReceiver.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import org.springframework.jms.annotation.JmsListener; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | //@Component 8 | public class RateReceiver { 9 | 10 | @JmsListener(destination = "${apress.jms.rate-queue}") 11 | public void processRate(Rate rate){ 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/RateReplyReceiver.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | import java.util.UUID; 6 | 7 | import org.springframework.jms.annotation.JmsListener; 8 | import org.springframework.messaging.Message; 9 | import org.springframework.messaging.handler.annotation.SendTo; 10 | import org.springframework.messaging.support.MessageBuilder; 11 | 12 | import com.apress.messaging.domain.Rate; 13 | 14 | //@Component 15 | public class RateReplyReceiver { 16 | 17 | 18 | @JmsListener(destination = "${apress.jms.rate-queue}") 19 | @SendTo("${apress.jms.rate-reply-queue}") 20 | public Message processRate(Rate rate){ 21 | 22 | //Process the Rate and return any significant value 23 | 24 | return MessageBuilder 25 | .withPayload("PROCCESSED") 26 | .setHeader("CODE", rate.getCode()) 27 | .setHeader("RATE", rate.getRate()) 28 | .setHeader("ID", UUID.randomUUID().toString()) 29 | .setHeader("DATE", new SimpleDateFormat("yyyy-MM-dd").format(new Date())) 30 | .build(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/RateSender.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.jms.core.JmsTemplate; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.domain.Rate; 8 | 9 | @Component 10 | public class RateSender { 11 | 12 | private JmsTemplate jmsTemplate; 13 | 14 | @Autowired 15 | public RateSender(JmsTemplate jmsTemplate){ 16 | this.jmsTemplate = jmsTemplate; 17 | } 18 | 19 | public void sendCurrency(String destination, Rate rate){ 20 | this.jmsTemplate.convertAndSend(destination,rate); 21 | } 22 | 23 | /* This code is for the reply-to-queue section 24 | 25 | @JmsListener(destination="${apress.jms.rate-reply-queue}") 26 | public void process(String body,@Header("CODE") String code){ 27 | 28 | } 29 | 30 | */ 31 | } 32 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/java/com/apress/messaging/jms/SimpleSender.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.jms.core.JmsTemplate; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class SimpleSender { 9 | 10 | private JmsTemplate jmsTemplate; 11 | 12 | @Autowired 13 | public SimpleSender(JmsTemplate jmsTemplate){ 14 | this.jmsTemplate = jmsTemplate; 15 | } 16 | 17 | public void sendMessage(String destination, String message){ 18 | this.jmsTemplate.convertAndSend(destination, message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "apress.jms.queue", 3 | "type": "java.lang.String", 4 | "description": "The queue name" 5 | },{ 6 | "name": "apress.jms.topic", 7 | "type": "java.lang.String", 8 | "description": "The topic name" 9 | },{ 10 | "name": "apress.jms.rate-queue", 11 | "type": "java.lang.String", 12 | "description": "The Rate queue name" 13 | 14 | },{ 15 | "name": "apress.jms.rate-reply-queue", 16 | "type": "java.lang.String", 17 | "description": "The Rate reply queue name" 18 | 19 | }]} 20 | 21 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Web 2 | spring.main.web-environment=false 3 | 4 | #Jackson 5 | #spring.jackson.date-format=yyyy-MM-dd 6 | 7 | #Default ActiveMQ properties 8 | spring.activemq.broker-url=tcp://localhost:61616 9 | spring.activemq.user=admin 10 | spring.activemq.password=admin 11 | 12 | 13 | #Apress Configuration 14 | apress.jms.queue=jms-demo 15 | apress.jms.rate-queue=rates 16 | apress.jms.rate-reply-queue=reply-rate 17 | 18 | 19 | #Enable Topic Messaging 20 | #spring.jms.pub-sub-domain=true 21 | 22 | #Apress Topic Configuration 23 | apress.jms.topic=rate-topic 24 | 25 | -------------------------------------------------------------------------------- /ch04/jms-sender/src/test/java/com/apress/messaging/JmsSenderApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JmsSenderApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/.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/ -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/JmsTopicSubscriberApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JmsTopicSubscriberApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JmsTopicSubscriberApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(JmsTopicSubscriberApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/config/JMSConfig.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(JMSProperties.class) 12 | public class JMSConfig { 13 | 14 | /* This is necessary when you want to send and Object without using Serializable.*/ 15 | @Bean 16 | public MessageConverter jacksonJmsMessageConverter() { 17 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 18 | converter.setTargetType(MessageType.TEXT); 19 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 20 | return converter; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/config/JMSProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="apress.jms") 6 | public class JMSProperties { 7 | 8 | private String topic; 9 | 10 | public String getTopic() { 11 | return topic; 12 | } 13 | 14 | public void setTopic(String topic) { 15 | this.topic = topic; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/java/com/apress/messaging/jms/RateTopicReceiver.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.jms; 2 | 3 | import org.springframework.jms.annotation.JmsListener; 4 | import org.springframework.stereotype.Component; 5 | 6 | import com.apress.messaging.domain.Rate; 7 | 8 | @Component 9 | public class RateTopicReceiver { 10 | 11 | @JmsListener(destination = "${apress.jms.topic}") 12 | public void processTopicRate(Rate rate){ 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "apress.jms.topic", 3 | "type": "java.lang.String", 4 | "description": "The topic name" 5 | }]} -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Web 2 | spring.main.web-environment=false 3 | 4 | #Default ActiveMQ properties 5 | spring.activemq.broker-url=tcp://localhost:61616 6 | spring.activemq.user=admin 7 | spring.activemq.password=admin 8 | 9 | #Enable Topic 10 | spring.jms.pub-sub-domain=true 11 | 12 | #Apress Topic Configuration 13 | apress.jms.topic=rates 14 | -------------------------------------------------------------------------------- /ch04/jms-topic-subscriber/src/test/java/com/apress/messaging/JmsTopicSubscriberApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JmsTopicSubscriberApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/RestApiJMSApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestApiJMSApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestApiJMSApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiJMSApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(String base, String date, Rate[] rates) { 13 | super(); 14 | this.base = base; 15 | this.date = date; 16 | this.rates = rates; 17 | } 18 | 19 | public String getBase() { 20 | return base; 21 | } 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | public String getDate() { 26 | return date; 27 | } 28 | public void setDate(String date) { 29 | this.date = date; 30 | } 31 | public Rate[] getRates() { 32 | return rates; 33 | } 34 | public void setRates(Rate[] rates) { 35 | this.rates = rates; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rate.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | }]} -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | spring.activemq.broker-url=tcp://localhost:61616 12 | spring.activemq.user=admin 13 | spring.activemq.password=admin 14 | 15 | #Rate App 16 | rate.jms.queue-name=rates 17 | rate.jms.reply-queue-name=reply-rate -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch04/rest-api-jms/src/test/java/com/apress/messaging/RestApiJMSApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiJMSApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch05/amqp-demo/.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/ -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(AmqpDemoApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/AnnotatedConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 4 | 5 | //@Component 6 | public class AnnotatedConsumer { 7 | 8 | @RabbitListener(queues="${apress.amqp.queue}") 9 | public void process(String message){ 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import org.springframework.amqp.core.Message; 4 | import org.springframework.amqp.core.MessageListener; 5 | 6 | //@Component 7 | public class Consumer implements MessageListener{ 8 | 9 | public void onMessage(Message message) { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/Producer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class Producer { 9 | 10 | private RabbitTemplate template; 11 | 12 | @Autowired 13 | public Producer(RabbitTemplate template){ 14 | this.template = template; 15 | } 16 | 17 | public void sendMessage(String exchange,String routingKey, String message){ 18 | this.template.convertAndSend(exchange,routingKey, message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | //@Component 8 | public class RateConsumer { 9 | 10 | @RabbitListener(queues="${apress.amqp.rate-queue}") 11 | public void messageHandler(Rate rate){ 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | 6 | import com.apress.messaging.domain.Rate; 7 | 8 | //@Component 9 | public class RateProducer { 10 | 11 | private RabbitTemplate template; 12 | 13 | @Autowired 14 | public RateProducer(RabbitTemplate template) { 15 | this.template = template; 16 | } 17 | 18 | public void sendRate(String exchange, String routingKey, Rate rate) { 19 | this.template.convertAndSend(exchange, routingKey, rate); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/ReplyToService.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | import java.util.UUID; 6 | 7 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 8 | import org.springframework.messaging.Message; 9 | import org.springframework.messaging.handler.annotation.SendTo; 10 | import org.springframework.messaging.support.MessageBuilder; 11 | 12 | //@Component 13 | public class ReplyToService { 14 | 15 | @RabbitListener(queues="${apress.amqp.queue}") 16 | @SendTo("${apress.amqp.reply-exchange-queue}") 17 | public Message replyToProcess(String message){ 18 | 19 | //More Processing here... 20 | 21 | return MessageBuilder 22 | .withPayload("PROCESSED:OK") 23 | .setHeader("PROCESSED", new SimpleDateFormat("yyyy-MM-dd").format(new Date())) 24 | .setHeader("CODE", UUID.randomUUID().toString()) 25 | .build(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/RpcClient.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | 4 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | 7 | //@Component 8 | public class RpcClient { 9 | 10 | private RabbitTemplate template; 11 | 12 | @Autowired 13 | public RpcClient(RabbitTemplate template) { 14 | this.template = template; 15 | } 16 | 17 | public Object sendMessage(String exchange, String routingKey, String message) { 18 | Object response = this.template.convertSendAndReceive(exchange, routingKey, message); 19 | return response; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/amqp/RpcServer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | import java.util.UUID; 6 | 7 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 8 | import org.springframework.messaging.Message; 9 | import org.springframework.messaging.support.MessageBuilder; 10 | 11 | //@Component 12 | public class RpcServer { 13 | 14 | @RabbitListener(queues="${apress.amqp.queue}") 15 | //@SendTo("${apress.amqp.reply-exchange-queue}") //Used when the client doesn't set replyTo. 16 | public Message process(String message){ 17 | 18 | //More Processing here... 19 | 20 | return MessageBuilder 21 | .withPayload("PROCESSED:OK") 22 | .setHeader("PROCESSED", new SimpleDateFormat("yyyy-MM-dd").format(new Date())) 23 | .setHeader("CODE", UUID.randomUUID().toString()) 24 | .build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/domain/Invoice.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class Invoice { 4 | 5 | private Float total; 6 | 7 | public Float getTotal() { 8 | return total; 9 | } 10 | 11 | public void setTotal(Float total) { 12 | this.total = total; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/domain/InvoiceWithTax.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class InvoiceWithTax { 4 | 5 | private Float tax; 6 | private Float subTotal; 7 | private Float total; 8 | 9 | public Float getTax() { 10 | return tax; 11 | } 12 | 13 | public void setTax(Float tax) { 14 | this.tax = tax; 15 | } 16 | 17 | public Float getTotal() { 18 | return total; 19 | } 20 | 21 | public void setTotal(Float total) { 22 | this.total = total; 23 | } 24 | 25 | public Float getSubTotal() { 26 | return subTotal; 27 | } 28 | 29 | public void setSubTotal(Float subTotal) { 30 | this.subTotal = subTotal; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/domain/Item.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class Item { 4 | 5 | private String id; 6 | private String name; 7 | private String label; 8 | private String description; 9 | private Float unitPrice; 10 | 11 | public String getId() { 12 | return id; 13 | } 14 | 15 | public void setId(String id) { 16 | this.id = id; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getLabel() { 28 | return label; 29 | } 30 | 31 | public void setLabel(String label) { 32 | this.label = label; 33 | } 34 | 35 | public String getDescription() { 36 | return description; 37 | } 38 | 39 | public void setDescription(String description) { 40 | this.description = description; 41 | } 42 | 43 | public Float getUnitPrice() { 44 | return unitPrice; 45 | } 46 | 47 | public void setUnitPrice(Float unitPrice) { 48 | this.unitPrice = unitPrice; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | public class Order { 4 | 5 | private String id; 6 | private Invoice invoice; 7 | private String description; 8 | 9 | public String getId() { 10 | return id; 11 | } 12 | 13 | public void setId(String id) { 14 | this.id = id; 15 | } 16 | 17 | public Invoice getInvoice() { 18 | return invoice; 19 | } 20 | 21 | public void setInvoice(Invoice invoice) { 22 | this.invoice = invoice; 23 | } 24 | 25 | public String getDescription() { 26 | return description; 27 | } 28 | 29 | public void setDescription(String description) { 30 | this.description = description; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/java/com/apress/messaging/listener/RabbitMQEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.amqp.rabbit.listener.ListenerContainerConsumerFailedEvent; 4 | import org.springframework.context.event.EventListener; 5 | 6 | //@Component 7 | public class RabbitMQEventListener { 8 | 9 | @EventListener 10 | public void handler(ListenerContainerConsumerFailedEvent container){ 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #Spring Boot - Web (Off) - command line parameter: --web=[true|false] 2 | spring.main.web-environment=${web:false} 3 | 4 | # Spring RabbitMQ 5 | # Uncomment the following line if the RabbitMQ is remote and modify the values accordingly 6 | #spring.rabbitmq.host=localhost 7 | #spring.rabbitmq.port=5672 8 | #spring.rabbitmq.username=guest 9 | #spring.rabbitmq.password=guest 10 | #spring.rabbitmq.virtual-host=/ 11 | 12 | # Apress AMQP 13 | apress.amqp.queue=spring-boot-queue 14 | 15 | # RPC Example 16 | apress.amqp.reply-queue=spring-boot-reply 17 | 18 | # Reply to an Exchange/Queue 19 | # To use this example is necessary: 20 | # 1. Create a Direct Exchange: my-exchange 21 | # 2. Create a Queue (any name, eg: my-queue) 22 | # 3. Bind my-exchange with the my-queue using a rounting key: my-reply-rk 23 | apress.amqp.reply-exchange-queue=my-exchange/my-reply-rk 24 | 25 | # Error Examples 26 | apress.amqp.error-queue=spring-boot-error-queue 27 | apress.amqp.error-exchange=spring-boot-error-exchange 28 | apress.amqp.error-routing-key=error 29 | 30 | # Apress AMQP - Currency/Rate Project 31 | apress.amqp.rate-queue=rate-queue 32 | -------------------------------------------------------------------------------- /ch05/amqp-demo/src/test/java/com/apress/messaging/AmqpDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class AmqpDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/.gitignore: -------------------------------------------------------------------------------- 1 | /.apt_generated/ 2 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/RestApiAMQPApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestApiAMQPApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestApiAMQPApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiAMQPApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateConsumer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateProducer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(String base, String date, Rate[] rates) { 13 | super(); 14 | this.base = base; 15 | this.date = date; 16 | this.rates = rates; 17 | } 18 | 19 | public String getBase() { 20 | return base; 21 | } 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | public String getDate() { 26 | return date; 27 | } 28 | public void setDate(String date) { 29 | this.date = date; 30 | } 31 | public Rate[] getRates() { 32 | return rates; 33 | } 34 | public void setRates(Rate[] rates) { 35 | this.rates = rates; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rata.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | }]} -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | #spring.activemq.broker-url=tcp://localhost:61616 12 | #spring.activemq.user=admin 13 | #spring.activemq.password=admin 14 | 15 | #Rate App 16 | #rate.jms.queue-name=rates 17 | #rate.jms.reply-queue-name=reply-rate -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch05/rest-api-amqp/src/test/java/com/apress/messaging/RestApiAMQPApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiAMQPApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch06/redis-demo/.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/ -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(RedisDemoApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/java/com/apress/messaging/config/SimpleRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "apress.redis") 6 | public class SimpleRedisProperties { 7 | 8 | private String topic; 9 | private String rate; 10 | 11 | public String getTopic() { 12 | return topic; 13 | } 14 | 15 | public void setTopic(String topic) { 16 | this.topic = topic; 17 | } 18 | 19 | public String getRate() { 20 | return rate; 21 | } 22 | 23 | public void setRate(String rate) { 24 | this.rate = rate; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/java/com/apress/messaging/redis/RateSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | @Component 8 | public class RateSubscriber { 9 | 10 | // If only one method defined, it must be named: handleMessage 11 | public void handleMessage(Rate rate){ 12 | // Process message here ... 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/java/com/apress/messaging/redis/Subscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class Subscriber { 7 | 8 | // If only one method defined, it must be named: handleMessage 9 | public void handleMessage(String message){ 10 | // Process message here ... 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "apress.redis.topic", 3 | "type": "java.lang.String", 4 | "description": "The Redis Topic name" 5 | },{ 6 | "name": "apress.redis.rate", 7 | "type": "java.lang.String", 8 | "description": "The Rate Topic name" 9 | }]} -------------------------------------------------------------------------------- /ch06/redis-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #Spring Boot - Web (Off) - command line parameter: --web=[true|false] 2 | spring.main.web-environment=${web:false} 3 | 4 | # Spring Redis 5 | 6 | # Apress Redis Queue 7 | apress.redis.topic=spring-boot-chat 8 | 9 | # Rate 10 | apress.redis.rate=currency-rate 11 | 12 | 13 | # Debug 14 | #debug=true -------------------------------------------------------------------------------- /ch06/redis-demo/src/test/java/com/apress/messaging/RedisDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RedisDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/.gitignore: -------------------------------------------------------------------------------- 1 | /.apt_generated/ 2 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/RestApiAMQPApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestApiAMQPApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestApiAMQPApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiAMQPApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateConsumer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateProducer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/config/RateRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.redis") 6 | public class RateRedisProperties { 7 | 8 | private String topic; 9 | 10 | public String getTopic() { 11 | return topic; 12 | } 13 | 14 | public void setTopic(String topic) { 15 | this.topic = topic; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(String base, String date, Rate[] rates) { 13 | super(); 14 | this.base = base; 15 | this.date = date; 16 | this.rates = rates; 17 | } 18 | 19 | public String getBase() { 20 | return base; 21 | } 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | public String getDate() { 26 | return date; 27 | } 28 | public void setDate(String date) { 29 | this.date = date; 30 | } 31 | public Rate[] getRates() { 32 | return rates; 33 | } 34 | public void setRates(Rate[] rates) { 35 | this.rates = rates; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/redis/RateRedisSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | @Component 8 | public class RateRedisSubscriber { 9 | 10 | // If only one method defined, it must be named: handleMessage 11 | public void handleMessage(Rate rate) { 12 | // Process message here ... 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rata.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | },{ 10 | "name": "rate.redis.topic", 11 | "type": "java.lang.String", 12 | "description": "The Redis Rate topic" 13 | }]} -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | #spring.activemq.broker-url=tcp://localhost:61616 12 | #spring.activemq.user=admin 13 | #spring.activemq.password=admin 14 | 15 | #Rate App 16 | #rate.jms.queue-name=rates 17 | #rate.jms.reply-queue-name=reply-rate 18 | 19 | #Rate Redis 20 | #rate.redis.topic=rates-topic 21 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch06/rest-api-redis/src/test/java/com/apress/messaging/RestApiAMQPApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiAMQPApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/.gitignore: -------------------------------------------------------------------------------- 1 | /.apt_generated/ 2 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/RestApiWebSocketsApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | import com.apress.messaging.domain.Rate; 11 | import com.apress.messaging.repository.RateRepository; 12 | 13 | @SpringBootApplication 14 | public class RestApiWebSocketsApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(RestApiWebSocketsApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public CommandLineRunner data(RateRepository repository) { 22 | return (args) -> { 23 | repository.save(new Rate("EUR",0.88857F,new Date())); 24 | repository.save(new Rate("JPY",102.17F,new Date())); 25 | repository.save(new Rate("MXN",19.232F,new Date())); 26 | repository.save(new Rate("GBP",0.75705F,new Date())); 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiWebSocketsApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateConsumer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateProducer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/config/RateRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.redis") 6 | public class RateRedisProperties { 7 | 8 | private String topic; 9 | 10 | public String getTopic() { 11 | return topic; 12 | } 13 | 14 | public void setTopic(String topic) { 15 | this.topic = topic; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/config/RateWebSocketsProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "rate.ws") 6 | public class RateWebSocketsProperties { 7 | 8 | private String app = "/rest-api-ws"; 9 | private String broker = "/rate"; 10 | private String endpoint = "/stomp"; 11 | 12 | public String getApp() { 13 | return app; 14 | } 15 | 16 | public void setApp(String app) { 17 | this.app = app; 18 | } 19 | 20 | public String getBroker() { 21 | return broker; 22 | } 23 | 24 | public void setBroker(String broker) { 25 | this.broker = broker; 26 | } 27 | 28 | public String getEndpoint() { 29 | return endpoint; 30 | } 31 | 32 | public void setEndpoint(String endpoint) { 33 | this.endpoint = endpoint; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(){} 13 | 14 | public CurrencyExchange(String base, String date, Rate[] rates) { 15 | super(); 16 | this.base = base; 17 | this.date = date; 18 | this.rates = rates; 19 | } 20 | 21 | public String getBase() { 22 | return base; 23 | } 24 | public void setBase(String base) { 25 | this.base = base; 26 | } 27 | public String getDate() { 28 | return date; 29 | } 30 | public void setDate(String date) { 31 | this.date = date; 32 | } 33 | public Rate[] getRates() { 34 | return rates; 35 | } 36 | public void setRates(Rate[] rates) { 37 | this.rates = rates; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/redis/RateRedisSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | @Component 8 | public class RateRedisSubscriber { 9 | 10 | // If only one method defined, it must be named: handleMessage 11 | public void handleMessage(Rate rate) { 12 | // Process message here ... 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rata.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | },{ 10 | "name": "rate.redis.topic", 11 | "type": "java.lang.String", 12 | "description": "The Redis Rate topic" 13 | }]} -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | #spring.activemq.broker-url=tcp://localhost:61616 12 | #spring.activemq.user=admin 13 | #spring.activemq.password=admin 14 | 15 | #JMS Rate App 16 | #rate.jms.queue-name=rates 17 | #rate.jms.reply-queue-name=reply-rate 18 | 19 | #Rate Redis 20 | #rate.redis.topic=rates-topic 21 | 22 | #WebSockets 23 | #rate.ws.endpoint=/stomp 24 | #rate.ws.broker=/rate 25 | #rate.ws.app=/rest-api-ws 26 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch07/rest-api-websockets/src/test/java/com/apress/messaging/RestApiWebSocketsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiWebSocketsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch07/websocket-demo/.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/ -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(WebSocketsDemoApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/java/com/apress/messaging/config/LlWebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.socket.config.annotation.EnableWebSocket; 5 | import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 6 | import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 7 | 8 | import com.apress.messaging.web.socket.LlWebSocketHandler; 9 | 10 | @Configuration 11 | @EnableWebSocket 12 | public class LlWebSocketConfig implements WebSocketConfigurer{ 13 | 14 | LlWebSocketHandler handler; 15 | 16 | public LlWebSocketConfig(LlWebSocketHandler handler){ 17 | this.handler = handler; 18 | } 19 | 20 | @Override 21 | public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 22 | registry.addHandler(this.handler, "/llws"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/java/com/apress/messaging/controller/SimpleController.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.controller; 2 | 3 | import org.springframework.messaging.handler.annotation.MessageMapping; 4 | import org.springframework.messaging.handler.annotation.SendTo; 5 | import org.springframework.stereotype.Controller; 6 | 7 | import com.apress.messaging.domain.ChatMessage; 8 | 9 | @Controller 10 | public class SimpleController { 11 | 12 | @MessageMapping("${apress.ws.mapping}") 13 | @SendTo("/topic/chat-room") 14 | public ChatMessage chatRoom(ChatMessage message) { 15 | return message; 16 | } 17 | 18 | 19 | /* Enable for a dynamic destination */ 20 | /* 21 | @MessageMapping("${apress.ws.mapping}/{room}") 22 | @SendTo("/topic/chat-room/{user}") 23 | public ChatMessage directChatRoom(@DestinationVariable("room")String room 24 | ,@DestinationVariable("user")String user,ChatMessage message) { 25 | 26 | return message; 27 | } 28 | */ 29 | } 30 | -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/java/com/apress/messaging/web/socket/LlWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.web.socket; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.web.socket.TextMessage; 5 | import org.springframework.web.socket.WebSocketSession; 6 | import org.springframework.web.socket.handler.TextWebSocketHandler; 7 | 8 | @Component 9 | public class LlWebSocketHandler extends TextWebSocketHandler{ 10 | 11 | 12 | @Override 13 | public void afterConnectionEstablished(WebSocketSession session) throws Exception { 14 | super.afterConnectionEstablished(session); 15 | } 16 | 17 | @Override 18 | public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 19 | System.out.println(">>>> " + message); 20 | 21 | //Enable this if you want to return the Message to the Client 22 | //session.sendMessage(message); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "apress.ws.topic", 3 | "type": "java.lang.String", 4 | "description": "The Web Socket Topic name" 5 | },{ 6 | "name": "apress.ws.app-destination-prefix", 7 | "type": "java.lang.String", 8 | "description": "The Application destination prefix" 9 | },{ 10 | "name": "apress.ws.rate", 11 | "type": "java.lang.String", 12 | "description": "The Web Socket Rate Topic name" 13 | },{ 14 | "name": "apress.ws.mapping", 15 | "type": "java.lang.String", 16 | "description": "The Web Socket Mapping that accept incoming web socket messages" 17 | },{ 18 | "name": "apress.ws.endpoint", 19 | "type": "java.lang.String", 20 | "description": "The Web Socket Endpoint path" 21 | }]} -------------------------------------------------------------------------------- /ch07/websocket-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring WebSockets 2 | spring.aop.proxy-target-class=true 3 | server.port=${port:8080} 4 | 5 | # Apress WebSockets 6 | apress.ws.endpoint=/stomp-endpoint 7 | apress.ws.app-destination-prefix=/my-app 8 | apress.ws.mapping=/chat-room 9 | apress.ws.mapping-reply=${apress.ws.topic}${apress.ws.mapping} 10 | apress.ws.topic=/topic 11 | 12 | 13 | # Rate 14 | 15 | 16 | # Debug 17 | #debug=true -------------------------------------------------------------------------------- /ch07/websocket-demo/src/test/java/com/apress/messaging/WebSocketsDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class WebSocketsDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch08/rest-api-si/.gitignore: -------------------------------------------------------------------------------- 1 | /.apt_generated/ 2 | -------------------------------------------------------------------------------- /ch08/rest-api-si/rates-2017-02-21.txt: -------------------------------------------------------------------------------- 1 | {"code":"EUR","rate":0.82857,"date":"2017-02-15"} 2 | {"code":"JPY","rate":105.17,"date":"2017-02-15"} 3 | {"code":"MXN","rate":22.232,"date":"2017-02-15"} 4 | {"code":"GBP","rate":0.75705,"date":"2017-02-16"} -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/RestApiSpiApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestApiSpiApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestApiSpiApplication.class, args); 11 | } 12 | 13 | /* 14 | @Bean 15 | public CommandLineRunner data(RateRepository repository) { 16 | return (args) -> { 17 | repository.save(new Rate("EUR",0.88857F,new Date())); 18 | repository.save(new Rate("JPY",102.17F,new Date())); 19 | repository.save(new Rate("MXN",19.232F,new Date())); 20 | repository.save(new Rate("GBP",0.75705F,new Date())); 21 | }; 22 | } 23 | */ 24 | } 25 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiSpiApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateConsumer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateProducer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/config/RateRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.redis") 6 | public class RateRedisProperties { 7 | 8 | private String topic; 9 | 10 | public String getTopic() { 11 | return topic; 12 | } 13 | 14 | public void setTopic(String topic) { 15 | this.topic = topic; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/config/RateWebSocketsProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "rate.ws") 6 | public class RateWebSocketsProperties { 7 | 8 | private String app = "/rest-api-ws"; 9 | private String broker = "/rate"; 10 | private String endpoint = "/stomp"; 11 | 12 | public String getApp() { 13 | return app; 14 | } 15 | 16 | public void setApp(String app) { 17 | this.app = app; 18 | } 19 | 20 | public String getBroker() { 21 | return broker; 22 | } 23 | 24 | public void setBroker(String broker) { 25 | this.broker = broker; 26 | } 27 | 28 | public String getEndpoint() { 29 | return endpoint; 30 | } 31 | 32 | public void setEndpoint(String endpoint) { 33 | this.endpoint = endpoint; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(){} 13 | 14 | public CurrencyExchange(String base, String date, Rate[] rates) { 15 | super(); 16 | this.base = base; 17 | this.date = date; 18 | this.rates = rates; 19 | } 20 | 21 | public String getBase() { 22 | return base; 23 | } 24 | public void setBase(String base) { 25 | this.base = base; 26 | } 27 | public String getDate() { 28 | return date; 29 | } 30 | public void setDate(String date) { 31 | this.date = date; 32 | } 33 | public Rate[] getRates() { 34 | return rates; 35 | } 36 | public void setRates(Rate[] rates) { 37 | this.rates = rates; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/integration/RateServiceActivator.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.messaging.handler.annotation.Headers; 6 | import org.springframework.stereotype.Component; 7 | 8 | import com.apress.messaging.annotation.Log; 9 | import com.apress.messaging.domain.Rate; 10 | 11 | @Component 12 | public class RateServiceActivator { 13 | 14 | @Log(printParamsValues=true) 15 | public void process(Rate rate, @Headers Map headers){ 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/redis/RateRedisSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | @Component 8 | public class RateRedisSubscriber { 9 | 10 | // If only one method defined, it must be named: handleMessage 11 | public void handleMessage(Rate rate) { 12 | // Process message here ... 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rata.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | },{ 10 | "name": "rate.redis.topic", 11 | "type": "java.lang.String", 12 | "description": "The Redis Rate topic" 13 | }]} -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | #spring.activemq.broker-url=tcp://localhost:61616 12 | #spring.activemq.user=admin 13 | #spring.activemq.password=admin 14 | 15 | #JMS Rate App 16 | #rate.jms.queue-name=rates 17 | #rate.jms.reply-queue-name=reply-rate 18 | 19 | #Rate Redis 20 | #rate.redis.topic=rates-topic 21 | 22 | #WebSockets 23 | #rate.ws.endpoint=/stomp 24 | #rate.ws.broker=/rate 25 | #rate.ws.app=/rest-api-ws 26 | 27 | #SPI 28 | rate.spi.directory=. 29 | rate.spi.file-pattern=rates*.txt 30 | rate.spi.process-directory='output' 31 | rate.spi.queue=spi.rate 32 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch08/rest-api-si/src/test/java/com/apress/messaging/RestApiSpiApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiSpiApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch08/si-demo/.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/ -------------------------------------------------------------------------------- /ch08/si-demo/contacts.txt: -------------------------------------------------------------------------------- 1 | John, Doe, 2000-02-22, +1 345-834-6789, john.doe@company.com, true 2 | Silvia, DeMarcos, 1998-04-21, +1 345-884-6311, silvia.demarcos@company.com, false 3 | Jim, Wolf, 1999-08-22, +1 285-374-2357, jim.wolf@company.com, true -------------------------------------------------------------------------------- /ch08/si-demo/rates-2017-02-21.txt: -------------------------------------------------------------------------------- 1 | {"base":"USD","date":"2017-02-15","rates":[{"code":"EUR","rate":0.82857,"date":"2017-02-15"},{"code":"JPY","rate":105.17,"date":"2017-02-15"},{"code":"MXN","rate":22.232,"date":"2017-02-15"},{"code":"GBP","rate":0.75705,"date":"2017-02-16"}]} -------------------------------------------------------------------------------- /ch08/si-demo/src/main/java/com/apress/messaging/config/SpiProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "apress.spi") 6 | public class SpiProperties { 7 | 8 | private String directory; 9 | private String filePattern; 10 | private String exchange = ""; 11 | private String queue = "spi.rate"; 12 | 13 | public String getDirectory() { 14 | return directory; 15 | } 16 | 17 | public void setDirectory(String directory) { 18 | this.directory = directory; 19 | } 20 | 21 | public String getFilePattern() { 22 | return filePattern; 23 | } 24 | 25 | public void setFilePattern(String filePattern) { 26 | this.filePattern = filePattern; 27 | } 28 | 29 | public String getExchange() { 30 | return exchange; 31 | } 32 | 33 | public void setExchange(String exchange) { 34 | this.exchange = exchange; 35 | } 36 | 37 | public String getQueue() { 38 | return queue; 39 | } 40 | 41 | public void setQueue(String queue) { 42 | this.queue = queue; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/java/com/apress/messaging/controller/SimpleController.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.controller; 2 | 3 | public class SimpleController { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/java/com/apress/messaging/integration/PersonConverter.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | import org.springframework.core.convert.converter.Converter; 10 | import org.springframework.stereotype.Component; 11 | 12 | import com.apress.messaging.domain.Person; 13 | 14 | //@IntegrationConverter 15 | @Component 16 | public class PersonConverter implements Converter { 17 | 18 | @Override 19 | public Person convert(String str) { 20 | SimpleDateFormat df = new SimpleDateFormat("yyyyy-mm-dd"); 21 | List fields = Stream.of(str.split(",")).map(String::trim).collect(Collectors.toList()); 22 | try { 23 | return new Person(fields.get(0),fields.get(1),df.parse(fields.get(2)),fields.get(3),fields.get(4),Boolean.parseBoolean(fields.get(5))); 24 | } catch (ParseException e) { 25 | return null; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/java/com/apress/messaging/integration/SimpleMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import org.springframework.messaging.Message; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class SimpleMessageHandler { 8 | 9 | public void process(Message message){ 10 | 11 | } 12 | 13 | /* Enable this for a concrete Person Rate */ 14 | /* 15 | public void process(Person message){ 16 | 17 | } 18 | */ 19 | 20 | /* Enable this for a concrete Message Rate */ 21 | /* 22 | public void process(Rate message){ 23 | 24 | } 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/resources/META-INF/spring/integration/spi-file-to-jdbc.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # H2 Console 2 | spring.h2.console.enabled=true 3 | 4 | # Apress SPI properties 5 | apress.spi.directory=. 6 | apress.spi.file-pattern=contacts.txt 7 | 8 | apress.spi.queue=spi.rate 9 | -------------------------------------------------------------------------------- /ch08/si-demo/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS person; 2 | 3 | CREATE TABLE person ( 4 | id integer NOT NULL AUTO_INCREMENT, 5 | first varchar(150), 6 | last varchar(150), 7 | dob date, 8 | phone varchar(12), 9 | email varchar(150), 10 | friend boolean, 11 | PRIMARY KEY(id) 12 | ); -------------------------------------------------------------------------------- /ch08/si-demo/src/test/java/com/apress/messaging/SpiDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpiDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch09/app-starters/http/http-source-rabbit-1.1.2.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch09/app-starters/http/http-source-rabbit-1.1.2.RELEASE.jar -------------------------------------------------------------------------------- /ch09/app-starters/http/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar http-source-rabbit-1.1.2.RELEASE.jar --spring.cloud.stream.bindings.output.destination=simple-demo 3 | -------------------------------------------------------------------------------- /ch09/app-starters/log/log-sink-rabbit-1.1.1.RELEASE.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch09/app-starters/log/log-sink-rabbit-1.1.1.RELEASE.jar -------------------------------------------------------------------------------- /ch09/app-starters/log/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -jar log-sink-rabbit-1.1.1.RELEASE.jar --spring.cloud.stream.bindings.input.destination=simple-demo --server.port=8081 3 | -------------------------------------------------------------------------------- /ch09/cloud-stream-demo/.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/ -------------------------------------------------------------------------------- /ch09/cloud-stream-demo/src/main/java/com/apress/messaging/cloud/stream/SimpleSink.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.cloud.stream.annotation.StreamListener; 4 | import org.springframework.cloud.stream.messaging.Sink; 5 | 6 | //@EnableBinding(Sink.class) 7 | public class SimpleSink { 8 | 9 | 10 | @StreamListener(Sink.INPUT) 11 | public void process(String message){ 12 | 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ch09/cloud-stream-demo/src/main/resources/META-INF/spring.integration.properties: -------------------------------------------------------------------------------- 1 | # Headers to keep in between channel 2 | #spring.integration.readOnly.headers=contentType -------------------------------------------------------------------------------- /ch09/cloud-stream-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream 2 | 3 | # Message converter in channel INPUT (For the Processor and Sink streams) 4 | # spring.cloud.stream.bindings.input.content-type=text/plain 5 | 6 | # Message converter in channel OUTPUT (For the Source stream) 7 | #spring.cloud.stream.bindings.output.content-type=application/json -------------------------------------------------------------------------------- /ch09/cloud-stream-demo/src/test/java/com/apress/cloud/stream/CloudStreamDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.cloud.stream; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CloudStreamDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch09/cloud-stream-processor-demo/.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/ -------------------------------------------------------------------------------- /ch09/cloud-stream-processor-demo/src/main/java/com/apress/messaging/CloudStreamProcessorDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CloudStreamProcessorDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CloudStreamProcessorDemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch09/cloud-stream-processor-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream - Processor 2 | # Spring 3 | server.port=${port:8082} 4 | 5 | # Spring Cloud Stream 6 | spring.cloud.stream.bindings.input.destination=person 7 | spring.cloud.stream.bindings.output.destination=tickets 8 | 9 | spring.cloud.stream.bindings.output.content-type=application/json 10 | 11 | # Date Format 12 | spring.jackson.date-format=yyyy-MM-dd -------------------------------------------------------------------------------- /ch09/cloud-stream-processor-demo/src/test/java/com/apress/messging/CloudStreamProcessorDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CloudStreamProcessorDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch09/cloud-stream-sink-demo/.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/ -------------------------------------------------------------------------------- /ch09/cloud-stream-sink-demo/src/main/java/com/apress/messaging/CloudStreamSinkDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CloudStreamSinkDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CloudStreamSinkDemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch09/cloud-stream-sink-demo/src/main/java/com/apress/messaging/cloud/stream/TicketSinkProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "ticket") 6 | public class TicketSinkProperties { 7 | 8 | private String queue; 9 | private String exchange; 10 | 11 | public String getQueue() { 12 | return queue; 13 | } 14 | 15 | public void setQueue(String queue) { 16 | this.queue = queue; 17 | } 18 | 19 | public String getExchange() { 20 | return exchange; 21 | } 22 | 23 | public void setExchange(String exchange) { 24 | this.exchange = exchange; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ch09/cloud-stream-sink-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream - Sink 2 | # Spring 3 | server.port=${port:8083} 4 | 5 | # Spring Cloud Stream 6 | spring.cloud.stream.bindings.input.destination=tickets 7 | 8 | ticket.queue=processed.tickets -------------------------------------------------------------------------------- /ch09/cloud-stream-sink-demo/src/test/java/com/apress/messging/CloudStreamSinkDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CloudStreamSinkDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/.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/ -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/contacts.txt: -------------------------------------------------------------------------------- 1 | John, Doe, 2000-02-22, +1 345-834-6789, john.doe@company.com, true 2 | Silvia, DeMarcos, 1998-04-21, +1 345-884-6311, silvia.demarcos@company.com, false 3 | Jim, Wolf, 1999-08-22, +1 285-374-2357, jim.wolf@company.com, true -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/java/com/apress/messaging/CloudStreamSourceDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CloudStreamSourceDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CloudStreamSourceDemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/java/com/apress/messaging/cloud/stream/PersonFileProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | @ConfigurationProperties(prefix = "apress.stream.file") 8 | public class PersonFileProperties { 9 | 10 | private String directory; 11 | private String namePattern; 12 | 13 | public String getDirectory() { 14 | return directory; 15 | } 16 | 17 | public void setDirectory(String directory) { 18 | this.directory = directory; 19 | } 20 | 21 | public String getNamePattern() { 22 | return namePattern; 23 | } 24 | 25 | public void setNamePattern(String namePattern) { 26 | this.namePattern = namePattern; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/java/com/apress/messaging/domain/Rate.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Rate { 7 | 8 | private String code; 9 | private Float rate; 10 | private Date date; 11 | 12 | public Rate() { 13 | } 14 | 15 | public Rate(String base, Float rate, Date date) { 16 | super(); 17 | this.code = base; 18 | this.rate = rate; 19 | this.date = date; 20 | } 21 | 22 | public String getCode() { 23 | return code; 24 | } 25 | 26 | public void setCode(String code) { 27 | this.code = code; 28 | } 29 | 30 | public Float getRate() { 31 | return rate; 32 | } 33 | 34 | public void setRate(Float rate) { 35 | this.rate = rate; 36 | } 37 | 38 | public Date getDate() { 39 | return date; 40 | } 41 | 42 | public void setDate(Date date) { 43 | this.date = date; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | String format = new SimpleDateFormat("yyyy-MM-dd").format(date); 49 | return "Rate [code=" + code + ", rate=" + rate + ", date=" + format + "]"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/java/com/apress/messaging/integration/PersonConverter.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.Stream; 8 | 9 | import org.springframework.core.convert.converter.Converter; 10 | import org.springframework.stereotype.Component; 11 | 12 | import com.apress.messaging.domain.Person; 13 | 14 | @Component 15 | public class PersonConverter implements Converter { 16 | 17 | @Override 18 | public Person convert(String str) { 19 | SimpleDateFormat df = new SimpleDateFormat("yyyyy-mm-dd"); 20 | List fields = Stream.of(str.split(",")).map(String::trim).collect(Collectors.toList()); 21 | try { 22 | return new Person(fields.get(0),fields.get(1),df.parse(fields.get(2)),fields.get(3),fields.get(4),Boolean.parseBoolean(fields.get(5))); 23 | } catch (ParseException e) { 24 | return null; 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/java/com/apress/messaging/integration/SimpleMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import org.springframework.messaging.Message; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class SimpleMessageHandler { 8 | 9 | public void process(Message message){ 10 | 11 | } 12 | 13 | /* Enable this for a concrete Person Rate */ 14 | /* 15 | public void process(Person message){ 16 | 17 | } 18 | */ 19 | 20 | /* Enable this for a concrete Message Rate */ 21 | /* 22 | public void process(Rate message){ 23 | 24 | } 25 | */ 26 | } 27 | -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Spring Cloud Stream - Source 2 | # Spring 3 | server.port=${port:8081} 4 | 5 | # Spring Cloud Stream 6 | spring.cloud.stream.bindings.output.destination=person 7 | 8 | 9 | # Apress Cloud Stream 10 | apress.stream.file.directory=. 11 | apress.stream.file.name-pattern=*.txt -------------------------------------------------------------------------------- /ch09/cloud-stream-source-demo/src/test/java/com/apress/messging/CloudStreamSourceDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CloudStreamSourceDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/.gitignore: -------------------------------------------------------------------------------- 1 | /.apt_generated/ 2 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/output/rates-2017-02-21.processed: -------------------------------------------------------------------------------- 1 | Rate [code=EUR, rate=0.82857, date=2017-02-14] 2 | Rate [code=JPY, rate=105.17, date=2017-02-14] 3 | Rate [code=MXN, rate=22.232, date=2017-02-14] 4 | Rate [code=GBP, rate=0.75705, date=2017-02-15] 5 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/rates-2017-02-21.txt: -------------------------------------------------------------------------------- 1 | {"code":"EUR","rate":0.82857,"date":"2017-02-15"} 2 | {"code":"JPY","rate":105.17,"date":"2017-02-15"} 3 | {"code":"MXN","rate":22.232,"date":"2017-02-15"} 4 | {"code":"GBP","rate":0.75705,"date":"2017-02-16"} -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 9 | return application.sources(RestApiCloudStreamApplication.class); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/amqp/RateConsumer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateConsumer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/amqp/RateProducer.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.amqp; 2 | 3 | public class RateProducer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/annotation/Log.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | public @interface Log { 11 | boolean printParamsValues() default false; 12 | String callMethodWithNoParamsToString() default "toString"; 13 | } 14 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/annotation/ToUpper.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.PARAMETER) 10 | public @interface ToUpper { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/cloud/stream/RateExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.cloud.stream.annotation.Input; 4 | import org.springframework.cloud.stream.annotation.Output; 5 | import org.springframework.messaging.MessageChannel; 6 | import org.springframework.messaging.SubscribableChannel; 7 | 8 | public interface RateExchange { 9 | 10 | String INPUT = "rates"; 11 | String OUTPUT_EUR = "EUR"; 12 | String OUTPUT_JPY = "JPY"; 13 | 14 | 15 | @Input(RateExchange.INPUT) 16 | SubscribableChannel rates(); 17 | 18 | @Output(RateExchange.OUTPUT_EUR) 19 | MessageChannel eur(); 20 | 21 | @Output(RateExchange.OUTPUT_JPY) 22 | MessageChannel jpy(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/cloud/stream/RateProcessor.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.cloud.stream.annotation.EnableBinding; 4 | import org.springframework.cloud.stream.binding.BinderAwareChannelResolver; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.expression.spel.standard.SpelExpressionParser; 7 | import org.springframework.integration.annotation.ServiceActivator; 8 | import org.springframework.integration.router.AbstractMappingMessageRouter; 9 | import org.springframework.integration.router.ExpressionEvaluatingRouter; 10 | 11 | @EnableBinding(RateExchange.class) 12 | public class RateProcessor { 13 | 14 | @Bean 15 | @ServiceActivator(inputChannel = RateExchange.INPUT) 16 | public AbstractMappingMessageRouter router(BinderAwareChannelResolver channelResolver) { 17 | AbstractMappingMessageRouter router = new ExpressionEvaluatingRouter(new SpelExpressionParser().parseExpression("payload.code")); 18 | router.setDefaultOutputChannelName("default-output"); 19 | router.setChannelResolver(channelResolver); 20 | return router; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/cloud/stream/RateSink.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.cloud.stream; 2 | 3 | import org.springframework.cloud.stream.annotation.StreamListener; 4 | import org.springframework.integration.annotation.ServiceActivator; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.domain.Rate; 8 | 9 | //@EnableBinding(RateExchange.class) 10 | public class RateSink { 11 | 12 | @Log(printParamsValues=true) 13 | @ServiceActivator(inputChannel = RateExchange.OUTPUT_JPY) 14 | public void processJPY(Rate rate){ 15 | 16 | } 17 | 18 | @Log(printParamsValues=true) 19 | @StreamListener(RateExchange.OUTPUT_EUR) 20 | public void processEUR(Rate rate){ 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/config/RateJmsConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.jms.support.converter.MappingJackson2MessageConverter; 7 | import org.springframework.jms.support.converter.MessageConverter; 8 | import org.springframework.jms.support.converter.MessageType; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(RateProperties.class) 12 | public class RateJmsConfiguration { 13 | 14 | @Bean 15 | public MessageConverter jacksonJmsMessageConverter() { 16 | MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 17 | converter.setTargetType(MessageType.TEXT); 18 | converter.setTypeIdPropertyName("_class_"); // This value can be anything, it will save the JSON class name and it must be the same for sender/receiver 19 | return converter; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/config/RateProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.jms") 6 | public class RateProperties { 7 | 8 | private String queueName; 9 | private String replyQueueName; 10 | 11 | public String getQueueName() { 12 | return queueName; 13 | } 14 | 15 | public void setQueueName(String queueName) { 16 | this.queueName = queueName; 17 | } 18 | 19 | public String getReplyQueueName() { 20 | return replyQueueName; 21 | } 22 | 23 | public void setReplyQueueName(String replyQueueName) { 24 | this.replyQueueName = replyQueueName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/config/RateRedisProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix="rate.redis") 6 | public class RateRedisProperties { 7 | 8 | private String topic; 9 | 10 | public String getTopic() { 11 | return topic; 12 | } 13 | 14 | public void setTopic(String topic) { 15 | this.topic = topic; 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/config/RateWebSocketsProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "rate.ws") 6 | public class RateWebSocketsProperties { 7 | 8 | private String app = "/rest-api-ws"; 9 | private String broker = "/rate"; 10 | private String endpoint = "/stomp"; 11 | 12 | public String getApp() { 13 | return app; 14 | } 15 | 16 | public void setApp(String app) { 17 | this.app = app; 18 | } 19 | 20 | public String getBroker() { 21 | return broker; 22 | } 23 | 24 | public void setBroker(String broker) { 25 | this.broker = broker; 26 | } 27 | 28 | public String getEndpoint() { 29 | return endpoint; 30 | } 31 | 32 | public void setEndpoint(String endpoint) { 33 | this.endpoint = endpoint; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/domain/CurrencyExchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CurrencyExchange { 6 | 7 | public static final String BASE_CODE = "USD"; 8 | private String base; 9 | private String date; 10 | private Rate[] rates; 11 | 12 | public CurrencyExchange(){} 13 | 14 | public CurrencyExchange(String base, String date, Rate[] rates) { 15 | super(); 16 | this.base = base; 17 | this.date = date; 18 | this.rates = rates; 19 | } 20 | 21 | public String getBase() { 22 | return base; 23 | } 24 | public void setBase(String base) { 25 | this.base = base; 26 | } 27 | public String getDate() { 28 | return date; 29 | } 30 | public void setDate(String date) { 31 | this.date = date; 32 | } 33 | public Rate[] getRates() { 34 | return rates; 35 | } 36 | public void setRates(Rate[] rates) { 37 | this.rates = rates; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "CurrencyExchange [base=" + base + ", date=" + date + ", rates=" + Arrays.toString(rates) + "]"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/event/CurrencyConversionEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.CurrencyConversion; 6 | 7 | public class CurrencyConversionEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = -4481493963350551884L; 10 | private CurrencyConversion conversion; 11 | private String message; 12 | 13 | public CurrencyConversionEvent(Object source, CurrencyConversion conversion) { 14 | super(source); 15 | this.conversion = conversion; 16 | } 17 | 18 | public CurrencyConversionEvent(Object source, String message, CurrencyConversion conversion) { 19 | super(source); 20 | this.message = message; 21 | this.conversion = conversion; 22 | } 23 | 24 | public CurrencyConversion getConversion(){ 25 | return conversion; 26 | } 27 | 28 | public String getMessage(){ 29 | return message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/event/CurrencyEvent.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.event; 2 | 3 | import org.springframework.context.ApplicationEvent; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | public class CurrencyEvent extends ApplicationEvent { 8 | 9 | private static final long serialVersionUID = 889202626288526113L; 10 | private Rate rate; 11 | 12 | public CurrencyEvent(Object source,Rate rate) { 13 | super(source); 14 | this.rate = rate; 15 | } 16 | 17 | public Rate getRate(){ 18 | return this.rate; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/exception/BadCodeRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.exception; 2 | 3 | import com.apress.messaging.domain.CurrencyConversion; 4 | import com.apress.messaging.domain.Rate; 5 | 6 | public class BadCodeRuntimeException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -2411444965751028974L; 9 | private CurrencyConversion conversion; 10 | private Rate rate; 11 | 12 | public BadCodeRuntimeException(String message) { 13 | super(message); 14 | } 15 | 16 | public BadCodeRuntimeException(String message,CurrencyConversion conversion) { 17 | super(message); 18 | this.conversion = conversion; 19 | } 20 | 21 | public BadCodeRuntimeException(String message,Rate rate) { 22 | super(message); 23 | this.rate = rate; 24 | } 25 | 26 | public CurrencyConversion getConversion(){ 27 | return conversion; 28 | } 29 | 30 | public Rate getRate(){ 31 | return rate; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/integration/RateServiceActivator.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.integration; 2 | 3 | import java.util.Map; 4 | 5 | import org.springframework.messaging.handler.annotation.Headers; 6 | import org.springframework.stereotype.Component; 7 | 8 | import com.apress.messaging.annotation.Log; 9 | import com.apress.messaging.domain.Rate; 10 | 11 | @Component 12 | public class RateServiceActivator { 13 | 14 | @Log(printParamsValues=true) 15 | public void process(Rate rate, @Headers Map headers){ 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/listener/RateEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.transaction.event.TransactionalEventListener; 5 | 6 | import com.apress.messaging.annotation.Log; 7 | import com.apress.messaging.event.CurrencyEvent; 8 | 9 | @Component 10 | public class RateEventListener { 11 | 12 | //@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) 13 | @TransactionalEventListener 14 | @Log(printParamsValues=true,callMethodWithNoParamsToString="getRate") 15 | public void processEvent(CurrencyEvent event){ } 16 | } 17 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/listener/RestApiEventsListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.boot.actuate.metrics.CounterService; 5 | import org.springframework.context.ApplicationEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.context.support.ServletRequestHandledEvent; 9 | 10 | import com.apress.messaging.annotation.Log; 11 | 12 | @Component 13 | public class RestApiEventsListener implements ApplicationListener{ 14 | 15 | private static final String LATEST = "/currency/latest"; 16 | 17 | @Autowired 18 | private CounterService counterService; 19 | 20 | @Log(printParamsValues=true) 21 | public void onApplicationEvent(ApplicationEvent event) { 22 | if(event instanceof ServletRequestHandledEvent){ 23 | if(((ServletRequestHandledEvent)event).getRequestUrl().equals(LATEST)){ 24 | counterService.increment("url.currency.lastest.hits"); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/listener/RestAppEventListener.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.listener; 2 | 3 | import org.springframework.boot.context.event.SpringApplicationEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.stereotype.Component; 6 | 7 | import com.apress.messaging.annotation.Log; 8 | 9 | @Component 10 | public class RestAppEventListener { 11 | 12 | //@EventListener(condition = "#springApp.args.length > 1") 13 | //@EventListener({CurrencyEvent.class,CurrencyConversionEvent.class}) 14 | //@Order(Ordered.HIGHEST_PRECEDENCE) 15 | //@Async 16 | @EventListener 17 | @Log(printParamsValues=true) 18 | public void restAppHandler(SpringApplicationEvent springApp){ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/redis/RateRedisSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.redis; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import com.apress.messaging.domain.Rate; 6 | 7 | @Component 8 | public class RateRedisSubscriber { 9 | 10 | // If only one method defined, it must be named: handleMessage 11 | public void handleMessage(Rate rate) { 12 | // Process message here ... 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/java/com/apress/messaging/repository/RateRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | import com.apress.messaging.domain.Rate; 9 | 10 | public interface RateRepository extends JpaRepository{ 11 | List findByDate(Date date); 12 | Rate findByDateAndCode(Date date,String code); 13 | } 14 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | {"properties": [{ 2 | "name": "rata.jms.queue-name", 3 | "type": "java.lang.String", 4 | "description": "The Rate Queue name" 5 | },{ 6 | "name": "rate.jms.reply-queue-name", 7 | "type": "java.lang.String", 8 | "description": "The Reply Rate Queue name" 9 | },{ 10 | "name": "rate.redis.topic", 11 | "type": "java.lang.String", 12 | "description": "The Redis Rate topic" 13 | }]} -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #spring.h2.console.enabled=true 2 | #server.error.whitelabel.enabled=false 3 | 4 | #spring.aop.auto=true 5 | #spring.aop.proxy-target-class=true 6 | 7 | #Jackson 8 | #spring.jackson.date-format=yyyy-MM-dd 9 | 10 | #Default ActiveMQ properties 11 | #spring.activemq.broker-url=tcp://localhost:61616 12 | #spring.activemq.user=admin 13 | #spring.activemq.password=admin 14 | 15 | #JMS Rate App 16 | #rate.jms.queue-name=rates 17 | #rate.jms.reply-queue-name=reply-rate 18 | 19 | #Rate Redis 20 | #rate.redis.topic=rates-topic 21 | 22 | #WebSockets 23 | #rate.ws.endpoint=/stomp 24 | #rate.ws.broker=/rate 25 | #rate.ws.app=/rest-api-ws 26 | 27 | #SPI 28 | #rate.spi.directory=. 29 | #rate.spi.file-pattern=rates*.txt 30 | #rate.spi.process-directory='output' 31 | #rate.spi.queue=spi.rate 32 | 33 | #Cloud Stream 34 | spring.cloud.stream.bindings.input.destination=rates 35 | spring.cloud.stream.bindings.output.destination=rates 36 | 37 | spring.cloud.stream.bindings.output.content-type=application/json 38 | spring.jackson.date-format=yyyy-MM-dd -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/resources/public/error/4xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/main/resources/public/error/5xx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error: BAD REQUEST!

4 |

5 | Take a look at the Body/Path/Parameter format. 6 |

7 | 8 | -------------------------------------------------------------------------------- /ch09/rest-api-cloud-stream/src/test/java/com/apress/messaging/RestApiCloudStreamApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RestApiCloudStreamApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch10/reactor-demo/.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/ -------------------------------------------------------------------------------- /ch10/reactor-demo/src/main/java/com/apress/messaging/domain/Exchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | import java.util.SortedMap; 6 | 7 | public class Exchange { 8 | 9 | private String base = "USD"; 10 | private SortedMap rates; 11 | private Date timestamp; 12 | 13 | public Exchange(SortedMap rates, Date timestamp) { 14 | this.rates = rates; 15 | this.timestamp = timestamp; 16 | } 17 | 18 | public String getBase() { 19 | return base; 20 | } 21 | 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | 26 | public Map getRates() { 27 | return rates; 28 | } 29 | 30 | public void setRates(SortedMap rates) { 31 | this.rates = rates; 32 | } 33 | 34 | public Date getTimestamp() { 35 | return timestamp; 36 | } 37 | 38 | public void setTimestamp(Date timestamp) { 39 | this.timestamp = timestamp; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "Exchange [base=" + base + ", rates=" + rates + ", timestamp=" + timestamp + "]"; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /ch10/reactor-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch10/reactor-demo/src/main/resources/application.properties -------------------------------------------------------------------------------- /ch10/reactor-demo/src/test/java/com/apress/messaging/ReactorDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ReactorDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch10/rxjava-demo/.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/ -------------------------------------------------------------------------------- /ch10/rxjava-demo/src/main/java/com/apress/messaging/domain/Exchange.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | import java.util.SortedMap; 6 | 7 | public class Exchange { 8 | 9 | private String base = "USD"; 10 | private SortedMap rates; 11 | private Date timestamp; 12 | 13 | public Exchange(SortedMap rates, Date timestamp) { 14 | this.rates = rates; 15 | this.timestamp = timestamp; 16 | } 17 | 18 | public String getBase() { 19 | return base; 20 | } 21 | 22 | public void setBase(String base) { 23 | this.base = base; 24 | } 25 | 26 | public Map getRates() { 27 | return rates; 28 | } 29 | 30 | public void setRates(SortedMap rates) { 31 | this.rates = rates; 32 | } 33 | 34 | public Date getTimestamp() { 35 | return timestamp; 36 | } 37 | 38 | public void setTimestamp(Date timestamp) { 39 | this.timestamp = timestamp; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "Exchange [base=" + base + ", rates=" + rates + ", timestamp=" + timestamp + "]"; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /ch10/rxjava-demo/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | basic: 3 | enabled: false 4 | 5 | yahoo: 6 | client-id: dj0yJmk9emcxQU5XQWVaTXY2JmQ9WVdrOVJtWnVZV0ZJTm0wbWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD00Zg-- 7 | client-secret: 2134dfca8d11673217d1768741428fc598daa447 8 | user-authorization-uri: https://api.login.yahoo.com/oauth2/request_auth 9 | access-token-uri: https://api.login.yahoo.com/oauth2/get_token 10 | grant-type: password 11 | token-name: token -------------------------------------------------------------------------------- /ch10/rxjava-demo/src/test/java/com/apress/messaging/RxJavaDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RxJavaDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/.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/ -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/src/main/java/com/apress/messaging/config/ReactiveConfig.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.integration.dsl.channel.MessageChannels; 6 | import org.springframework.messaging.SubscribableChannel; 7 | 8 | @Configuration 9 | public class ReactiveConfig { 10 | 11 | @Bean 12 | public SubscribableChannel personChannel(){ 13 | return MessageChannels.publishSubscribe().get(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/src/main/java/com/apress/messaging/domain/Person.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.mongodb.core.mapping.Document; 5 | 6 | @Document 7 | public class Person { 8 | 9 | @Id 10 | private String id; 11 | private String name; 12 | private Integer age; 13 | 14 | public Person(){} 15 | 16 | public Person(String name, Integer age) { 17 | this.name = name; 18 | this.age = age; 19 | } 20 | 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | public void setId(String id) { 26 | this.id = id; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | public Integer getAge() { 38 | return age; 39 | } 40 | 41 | public void setAge(Integer age) { 42 | this.age = age; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/src/main/java/com/apress/messaging/repository/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.stream.Stream; 4 | 5 | import org.springframework.data.mongodb.repository.MongoRepository; 6 | import org.springframework.data.mongodb.repository.Query; 7 | 8 | import com.apress.messaging.domain.Person; 9 | 10 | public interface PersonRepository extends MongoRepository{ 11 | 12 | //CompletableFuture getById(String id); 13 | 14 | @Query("{}") 15 | Stream getAll(); 16 | } -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch10/spring-web-flux-reactive/src/main/resources/application.properties -------------------------------------------------------------------------------- /ch10/spring-web-flux-reactive/src/test/java/com/apress/messaging/SpringWebFluxReactiveApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringWebFluxReactiveApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch10/spring-web-flux/.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/ -------------------------------------------------------------------------------- /ch10/spring-web-flux/src/main/java/com/apress/messaging/domain/Person.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.domain; 2 | 3 | import org.springframework.data.annotation.Id; 4 | import org.springframework.data.mongodb.core.mapping.Document; 5 | 6 | @Document 7 | public class Person { 8 | 9 | @Id 10 | private String id; 11 | private String name; 12 | private Integer age; 13 | 14 | public Person(){} 15 | 16 | public Person(String name, Integer age) { 17 | this.name = name; 18 | this.age = age; 19 | } 20 | 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | public void setId(String id) { 26 | this.id = id; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | public Integer getAge() { 38 | return age; 39 | } 40 | 41 | public void setAge(Integer age) { 42 | this.age = age; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ch10/spring-web-flux/src/main/java/com/apress/messaging/repository/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.repository; 2 | 3 | import java.util.stream.Stream; 4 | 5 | import org.springframework.data.mongodb.repository.MongoRepository; 6 | import org.springframework.data.mongodb.repository.Query; 7 | 8 | import com.apress.messaging.domain.Person; 9 | 10 | public interface PersonRepository extends MongoRepository{ 11 | 12 | //CompletableFuture getById(String id); 13 | 14 | @Query("{}") 15 | Stream getAll(); 16 | } -------------------------------------------------------------------------------- /ch10/spring-web-flux/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch10/spring-web-flux/src/main/resources/application.properties -------------------------------------------------------------------------------- /ch10/spring-web-flux/src/test/java/com/apress/messaging/SpringWebFluxApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringWebFluxApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch10/web-emitter/.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/ -------------------------------------------------------------------------------- /ch10/web-emitter/src/main/java/com/apress/messaging/WebEmitterApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WebEmitterApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WebEmitterApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ch10/web-emitter/src/main/java/com/apress/messaging/config/EmitterProperties.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "emitter") 6 | public class EmitterProperties { 7 | 8 | private String directory; 9 | private String filePattern; 10 | 11 | public String getDirectory() { 12 | return directory; 13 | } 14 | 15 | public void setDirectory(String directory) { 16 | this.directory = directory; 17 | } 18 | 19 | public String getFilePattern() { 20 | return filePattern; 21 | } 22 | 23 | public void setFilePattern(String filePattern) { 24 | this.filePattern = filePattern; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /ch10/web-emitter/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | ## 2 | emitter.directory=${HOME}/Desktop/Names 3 | emitter.file-pattern=*.txt -------------------------------------------------------------------------------- /ch10/web-emitter/src/test/java/com/apress/messaging/WebEmitterApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class WebEmitterApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/circuit-breaker-service-demo/.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/ -------------------------------------------------------------------------------- /ch11/circuit-breaker-service-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /ch11/circuit-breaker-service-demo/src/test/java/com/apress/messaging/CircuitBreakerServiceDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CircuitBreakerServiceDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/config-client-demo/.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/ -------------------------------------------------------------------------------- /ch11/config-client-demo/src/main/java/com/apress/messaging/ConfigClientDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | @SpringBootApplication 11 | public class ConfigClientDemoApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(ConfigClientDemoApplication.class, args); 15 | } 16 | 17 | // This variable must be in the Github repository in the simple-config-client.properties file. 18 | @Value("${hello-world-message}") 19 | String message; 20 | 21 | @GetMapping("/") 22 | public String famousHelloWorld(){ 23 | return message; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ch11/config-client-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=simple-config-client 2 | 3 | -------------------------------------------------------------------------------- /ch11/config-client-demo/src/test/java/com/apress/messaging/ConfigClientDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ConfigClientDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/config-server-demo/.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/ -------------------------------------------------------------------------------- /ch11/config-server-demo/src/main/java/com/apress/messaging/ConfigServerDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class ConfigServerDemoApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ConfigServerDemoApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch11/config-server-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Default port 2 | server.port=${port:8888} 3 | 4 | # Spring Config Server 5 | spring.cloud.config.server.git.uri=https://github.com//your-repo-app-config.git 6 | -------------------------------------------------------------------------------- /ch11/config-server-demo/src/test/java/com/apress/messaging/ConfigServerDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ConfigServerDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/service-registry-client-demo/.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/ -------------------------------------------------------------------------------- /ch11/service-registry-client-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipeg48/spring-messaging/fd2c45a25f2b6264fe04f502c366ebdd0d601028/ch11/service-registry-client-demo/src/main/resources/application.properties -------------------------------------------------------------------------------- /ch11/service-registry-client-demo/src/test/java/com/apress/messaging/ServiceRegistryClientDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ServiceRegistryClientDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/service-registry-server-demo/.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/ -------------------------------------------------------------------------------- /ch11/service-registry-server-demo/src/main/java/com/apress/messaging/ServiceRegistryDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class ServiceRegistryDemoApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ServiceRegistryDemoApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ch11/service-registry-server-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Defautl Server Port 2 | server.port=${port:8761} 3 | 4 | # Eureka Configuration 5 | eureka.instance.hostname=localhost 6 | eureka.client.register-with-eureka=false 7 | eureka.client.fetch-registry=false 8 | eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ 9 | -------------------------------------------------------------------------------- /ch11/service-registry-server-demo/src/test/java/com/apress/messaging/ServiceRegistryDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ServiceRegistryDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ch11/service-registry-service-demo/.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/ -------------------------------------------------------------------------------- /ch11/service-registry-service-demo/src/main/java/com/apress/messaging/ServiceRegistryServiceDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | @SpringBootApplication 11 | @EnableDiscoveryClient 12 | public class ServiceRegistryServiceDemoApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ServiceRegistryServiceDemoApplication.class, args); 16 | } 17 | 18 | @GetMapping("/message") 19 | public String getMessage(){ 20 | return "Hello World from a Service Discovery"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch11/service-registry-service-demo/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8181 2 | 3 | spring.application.name=simple-service -------------------------------------------------------------------------------- /ch11/service-registry-service-demo/src/test/java/com/apress/messaging/ServiceRegistryServiceDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.apress.messaging; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ServiceRegistryServiceDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------