├── .gitignore ├── README.md ├── disruptor-billing-mbean-browser.PNG ├── pom.xml └── src └── main ├── java └── org │ └── anair │ ├── billing │ ├── disruptor │ │ ├── eventfactory │ │ │ └── BillingEvent.java │ │ ├── eventprocessor │ │ │ ├── BillingBusinessEventProcessor.java │ │ │ ├── BillingOutboundFormattingEventProcessor.java │ │ │ ├── BillingValidationEventProcessor.java │ │ │ ├── CorporateBillingBusinessEventProcessor.java │ │ │ ├── CustomerSpecificBillingBusinessEventProcessor.java │ │ │ └── JournalBillingEventProcessor.java │ │ ├── eventtranslator │ │ │ └── BillingEventTranslator.java │ │ └── publisher │ │ │ └── BillingEventPublisher.java │ ├── message │ │ └── listener │ │ │ └── BillingMessageListener.java │ ├── model │ │ └── BillingRecord.java │ └── service │ │ ├── BillingService.java │ │ └── BillingServiceImpl.java │ ├── datastream │ ├── disruptor │ │ ├── eventfactory │ │ │ └── DataStreamEvent.java │ │ ├── eventprocessor │ │ │ ├── FormatDataStreamEventProcessor.java │ │ │ ├── JournalDataStreamEventProcessor.java │ │ │ ├── ProcessADataStreamEventProcessor.java │ │ │ └── ProcessBDataStreamEventProcessor.java │ │ ├── eventtranslator │ │ │ └── DataStreamEventTranslator.java │ │ └── publisher │ │ │ └── DataStreamEventPublisher.java │ ├── message │ │ └── listener │ │ │ └── DataStreamMessageListener.java │ ├── model │ │ └── DataStream.java │ └── service │ │ ├── DatastreamService.java │ │ └── DatastreamServiceImpl.java │ ├── main │ └── SpringBootMQApplication.java │ └── spring │ └── config │ └── jms │ └── JmsConfiguration.java └── resources ├── application.yml ├── log4j.properties ├── spring-billing-disruptor.xml ├── spring-datastream-disruptor.xml ├── spring-jms.xml ├── spring-jmx.xml └── spring-service.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | target 3 | .classpath 4 | .project 5 | .springBeans -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spring Boot managed LMAX Disruptor Example project 2 | ================== 3 | This project uses [disruptor-spring-manager](https://github.com/anair-it/disruptor-spring-manager) to create disruptor spring beans and perform message transactions. 4 | The project uses spring boot to load up the application as a JMS listener. Integration with IBM Websphere MQ is required to run this project. Ofcourse you can make minor modifications to get this running against ActiveMQ etc. 5 | 6 | The example uses 2 disruptor beans. One to process billing records and another to process data streams. Both disruptors are configured as spring beans. 7 | 8 | Software pre-requisite 9 | -------- 10 | 1. JDK 8+ 11 | 2. Maven 3+ 12 | 3. Git 13 | 4. IBM Websphere MQ 7.5 server and client jars 14 | 5. Spring boot 1.5.x 15 | 16 | 17 | Setting up your environment 18 | ---- 19 | 1. Create a local queue manager. Name it as you wish. 20 | 2. Create a billing input queue. Name it as your wish. 21 | 3. Create a data stream input queue. Name it as your wish. 22 | 3. Start queue manager 23 | 4. Update _src/main/resources/application.yml_ with queue manager and queue names 24 | 25 | 26 | Configuring the disruptor 27 | ---------- 28 | 29 | [Billing disruptor spring configuration](src/main/webapp/WEB-INF/spring-billing-disruptor.xml) is based on the Consumer Dependency diamond graph that looks like this: 30 | 31 | | journalBillingEventProcessor | billingBusinessEventProcessor | 32 | | / | / | 33 | | / | / | 34 | billingEventPublisher -> Ring Buffer ->| - | - corporateBillingBusinessEventProcessor | -billingOutboundFormattingEventProcessor 35 | | \ | \ | 36 | | \ | \ | 37 | | billingValidationEventProcessor | customerSpecificBillingBusinessEventProcessor | 38 | 39 | 40 | --------- 41 | [Data Stream disruptor spring configuration](src/main/webapp/WEB-INF/spring-datastream-disruptor.xml) is based on the Consumer Dependency diamond graph that looks like this: 42 | 43 | | | processADataStreamEventProcessor | 44 | | | / | 45 | | | / | 46 | dataStreamEventPublisher -> Ring Buffer ->| - journalBillingEventProcessor | | -formatDataStreamEventProcessor 47 | | | \ | 48 | | | \ | 49 | | | processBDataStreamEventProcessor | 50 | 51 | 52 | Components 53 | ---- 54 | 1. [BillingRecord](src/main/java/org/anair/billing/model/BillingRecord.java) represents a Billing data model. 55 | 2. [BillingEvent](src/main/java/org/anair/billing/disruptor/eventfactory/BillingEvent.java) is used to preload the ringbuffer with BillingRecord objects so that they don't get GCed. 56 | 3. [BillingServiceImpl](src/main/java/org/anair/billing/service/BillingServiceImpl.java) performs billing business logic. 57 | 4. [BillingEventPublisher](src/main/java/org/anair/billing/disruptor/publisher/BillingEventPublisher.java) prepares to publish billing records to the ring buffer 58 | 5. [BillingEventTranslator](src/main/java/org/anair/billing/disruptor/eventtranslator/BillingEventTranslator.java) actually puts the data in ring buffer 59 | 6. [Event Processors/consumers](src/main/java/org/anair/billing/disruptor/eventprocessor) consume off the ring buffer and can perform parallel operations on the data 60 | 4. [BillingMessageListener](src/main/java/org/anair/billing/message/listener/BillingMessageListener.java) receives the MQ message and calls BillingEventPublisher. 61 | 5. [Billing Disruptor bean configuration](src/main/resources/spring-billing-disruptor.xml) 62 | 6. [Data stream Disruptor bean configuration](src/main/resources/spring-datastream-disruptor.xml) 63 | 7. [Spring configuration files](src/main/resources) 64 | 65 | Run it 66 | ---- 67 | 1.Start application 68 | 69 | mvn clean package 70 | java -jar target/disruptor-billing.jar 71 | You will see the following log messages that prints the disruptor configuration and dependency graph: 72 | 73 | 15:58:17.269 localhost-startStop-1 INFO [BaseDisruptorConfig] Created and configured LMAX disruptor {Thread Name: billingThread | Ringbuffer slot size: 1024 | Producer type: SINGLE | Wait strategy: BLOCKING} 74 | 15:58:17.279 localhost-startStop-1 INFO [DefaultDisruptorConfig] 75 | {JournalBillingEventProcessor | BillingValidationEventProcessor} -> {BillingBusinessEventProcessor | CorporateBillingBusinessEventProcessor | CustomerSpecificBillingBusinessEventProcessor} 76 | {BillingBusinessEventProcessor | CorporateBillingBusinessEventProcessor | CustomerSpecificBillingBusinessEventProcessor} -> {BillingOutboundFormattingEventProcessor} 77 | 15:58:17.289 localhost-startStop-1 INFO [JmxDisruptor] disruptor-spring:name=billingDisruptor,type=disruptor MBean defined for Disruptors. 78 | 79 | 2.Drop a message to any/both input queue. The message should be a long that relays the number of billing messages to be generated and processed. 80 | If you put in message of "20", 20 messages will be processed and here is the log output summary: 81 | 82 | 16:11:37.189 billingListenerContainer-1 INFO [BillingEventTranslator] Published Id [0] to sequence: 0 83 | 16:11:37.189 billingListenerContainer-1 INFO [BillingEventTranslator] Published Id [10] to sequence: 10 84 | 16:11:37.199 billingThread-1 INFO [BillingValidationEventProcessor] Sequence: 0. Id [0] 85 | 16:11:37.269 billingThread-1 INFO [BillingValidationEventProcessor] Sequence: 10. Id [10] 86 | 16:11:37.199 billingThread-2 INFO [JournalBillingEventProcessor] Sequence: 0. Id [0] 87 | 16:11:37.289 billingThread-3 INFO [BillingBusinessEventProcessor] Sequence: 0. Id [0] 88 | 16:11:37.289 billingThread-4 INFO [CustomerSpecificBillingBusinessEventProcessor] Sequence: 0. Id [0] 89 | 16:11:37.299 billingThread-5 INFO [CorporateBillingBusinessEventProcessor] Sequence: 0. Id [0] 90 | 16:11:37.299 billingThread-2 INFO [JournalBillingEventProcessor] Sequence: 10. Id [10] 91 | 16:11:37.309 billingThread-4 INFO [CustomerSpecificBillingBusinessEventProcessor] Sequence: 10. Id [10] 92 | 16:11:37.309 billingThread-3 INFO [BillingBusinessEventProcessor] Sequence: 10. Id [10] 93 | 16:11:37.309 billingThread-6 INFO [BillingOutboundFormattingEventProcessor] Sequence: 0. Id [0] 94 | 16:11:37.309 billingThread-5 INFO [CorporateBillingBusinessEventProcessor] Sequence: 10. Id [10] 95 | 16:11:37.310 billingThread-6 INFO [BillingOutboundFormattingEventProcessor] Sequence: 10. Id [10] 96 | 97 | 98 | JMX 99 | --- 100 | 1.On application context startup, all Disruptor beans will be automatically identified and registered as MBeans 101 | 2.View Disruptor MBeans through JConsole/Visual VM that looks like: ![MBean](disruptor-billing-mbean-browser.PNG) 102 | -------------------------------------------------------------------------------- /disruptor-billing-mbean-browser.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anair-it/disruptor-billing-example/4b0246730fd3d567f05f9cfb467d713867b59b09/disruptor-billing-mbean-browser.PNG -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.anair.disruptor.poc 5 | disruptor-billing 6 | jar 7 | 0.0.1 8 | disruptor-billing spring boot example application 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 1.5.4.RELEASE 14 | 15 | 16 | 17 | 18 | Anoop Nair 19 | anoopnair.it@gmail.com 20 | 21 | 22 | 23 | 2014 24 | 25 | 26 | 1.8 27 | 0.0.1 28 | 7.0.1.3 29 | 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-maven-plugin 36 | 37 | true 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 44 | ${java.version} 45 | ${java.version} 46 | UTF-8 47 | 48 | 49 | 50 | disruptor-billing 51 | 52 | 53 | src/main/resources 54 | true 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter-activemq 63 | 64 | 65 | org.anair.disruptor 66 | disruptor-spring-manager 67 | ${disruptor.spring.manager.version} 68 | 69 | 70 | javax.jms 71 | jms 72 | 1.1 73 | compile 74 | 75 | 76 | com.ibm 77 | com.ibm.mqjms 78 | ${wmq.version} 79 | jar 80 | compile 81 | 82 | 83 | com.ibm 84 | com.ibm.mq 85 | ${wmq.version} 86 | jar 87 | compile 88 | 89 | 90 | com.ibm 91 | com.ibm.dhbcore 92 | ${wmq.version} 93 | jar 94 | compile 95 | 96 | 97 | com.ibm 98 | com.ibm.mq.jmqi 99 | ${wmq.version} 100 | jar 101 | compile 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventfactory/BillingEvent.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventfactory; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | 5 | import com.lmax.disruptor.EventFactory; 6 | 7 | public class BillingEvent implements EventFactory { 8 | 9 | @Override 10 | public BillingRecord newInstance() { 11 | return new BillingRecord(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/BillingBusinessEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class BillingBusinessEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(BillingBusinessEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}", sequence, billingRecord.toString()); 20 | billingService.processBillingRecord(billingRecord); 21 | if(sequence%100==0){ 22 | LOG.info("Sequence: {}. {}",sequence, billingRecord.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setBillingService(BillingService billingService) { 28 | this.billingService = billingService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/BillingOutboundFormattingEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class BillingOutboundFormattingEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(BillingOutboundFormattingEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, billingRecord.toString()); 20 | billingService.formatBillingRecord(billingRecord); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, billingRecord.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setBillingService(BillingService billingService) { 28 | this.billingService = billingService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/BillingValidationEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class BillingValidationEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(BillingValidationEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Validating {}",sequence, billingRecord.toString()); 20 | billingService.validateBillingRecord(billingRecord); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, billingRecord.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setBillingService(BillingService billingService) { 28 | this.billingService = billingService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/CorporateBillingBusinessEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class CorporateBillingBusinessEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(CorporateBillingBusinessEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, billingRecord.toString()); 20 | billingService.processCorporateBillingRecord(billingRecord); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. ",sequence, billingRecord.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setBillingService(BillingService billingService) { 28 | this.billingService = billingService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/CustomerSpecificBillingBusinessEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class CustomerSpecificBillingBusinessEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(CustomerSpecificBillingBusinessEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | if(billingRecord.getCustomerName().startsWith("anair")){ 20 | LOG.trace("Sequence: {}. Going to process {}",sequence, billingRecord.toString()); 21 | billingService.processCustomerSpecificBillingRecord(billingRecord); 22 | if(sequence%10==0){ 23 | LOG.info("Sequence: {}. {}",sequence, billingRecord.toString()); 24 | } 25 | } 26 | } 27 | 28 | @Required 29 | public void setBillingService(BillingService billingService) { 30 | this.billingService = billingService; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventprocessor/JournalBillingEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventprocessor; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.billing.service.BillingService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class JournalBillingEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(JournalBillingEventProcessor.class); 14 | private BillingService billingService; 15 | 16 | @Override 17 | public void onEvent(BillingRecord billingRecord, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, billingRecord.toString()); 20 | billingService.journalBillingRecord(billingRecord); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, billingRecord.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setBillingService(BillingService billingService) { 28 | this.billingService = billingService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/eventtranslator/BillingEventTranslator.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.eventtranslator; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import com.lmax.disruptor.EventTranslator; 8 | 9 | public class BillingEventTranslator implements EventTranslator{ 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(BillingEventTranslator.class); 12 | private BillingRecord billingRecord; 13 | 14 | public BillingEventTranslator(BillingRecord billingRecord) { 15 | this.billingRecord = billingRecord; 16 | } 17 | 18 | @Override 19 | public void translateTo(BillingRecord billingRecord, long sequence) { 20 | billingRecord.setBillingId(this.billingRecord.getBillingId()); 21 | billingRecord.setBillable(this.billingRecord.isBillable()); 22 | billingRecord.setQuantity(this.billingRecord.getQuantity()); 23 | billingRecord.setBillableArtifactName(this.billingRecord.getBillableArtifactName()); 24 | billingRecord.setCustomerName(this.billingRecord.getCustomerName()); 25 | 26 | if(sequence%10==0){ 27 | LOG.info("Published {} to sequence: {}",billingRecord.toString(), sequence); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/disruptor/publisher/BillingEventPublisher.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.disruptor.publisher; 2 | 3 | import org.anair.billing.disruptor.eventtranslator.BillingEventTranslator; 4 | import org.anair.billing.model.BillingRecord; 5 | import org.anair.disruptor.DisruptorConfig; 6 | import org.anair.disruptor.publisher.EventPublisher; 7 | 8 | public class BillingEventPublisher implements EventPublisher{ 9 | 10 | private DisruptorConfig disruptorConfig; 11 | 12 | @Override 13 | public void publish(BillingRecord billingRecord){ 14 | disruptorConfig.publish(new BillingEventTranslator(billingRecord)); 15 | } 16 | 17 | @Override 18 | public void setDisruptorConfig(DisruptorConfig disruptorConfig) { 19 | this.disruptorConfig = disruptorConfig; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/message/listener/BillingMessageListener.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.message.listener; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.anair.disruptor.publisher.EventPublisher; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class BillingMessageListener { 10 | private static final Logger LOG = LoggerFactory.getLogger(BillingMessageListener.class); 11 | 12 | private EventPublisher billingEventPublisher; 13 | 14 | public void inMessage(String number){ 15 | if(StringUtils.isBlank(number) || !StringUtils.isNumeric(number.trim())){ 16 | LOG.error("Enter a valid long number"); 17 | return; 18 | } 19 | long inboundMessageCount = Long.parseLong(number.trim()); 20 | for(long l=0;l billingEventPublisher) { 42 | this.billingEventPublisher = billingEventPublisher; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/model/BillingRecord.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class BillingRecord implements Serializable { 6 | 7 | private static final long serialVersionUID = 3299746082013341934L; 8 | 9 | private long billingId; 10 | private boolean billable; 11 | private int quantity; 12 | private String billableArtifactName; 13 | private String customerName; 14 | 15 | 16 | public long getBillingId() { 17 | return billingId; 18 | } 19 | public void setBillingId(long billingId) { 20 | this.billingId = billingId; 21 | } 22 | public boolean isBillable() { 23 | return billable; 24 | } 25 | public void setBillable(boolean billable) { 26 | this.billable = billable; 27 | } 28 | public int getQuantity() { 29 | return quantity; 30 | } 31 | public void setQuantity(int quantity) { 32 | this.quantity = quantity; 33 | } 34 | public String getBillableArtifactName() { 35 | return billableArtifactName; 36 | } 37 | public void setBillableArtifactName(String billableArtifactName) { 38 | this.billableArtifactName = billableArtifactName; 39 | } 40 | public String getCustomerName() { 41 | return customerName; 42 | } 43 | public void setCustomerName(String customerName) { 44 | this.customerName = customerName; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "Id [" + billingId + "]"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/service/BillingService.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.service; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | 5 | public interface BillingService { 6 | static final long delay = 999999L; 7 | 8 | void validateBillingRecord(BillingRecord billingRecord); 9 | 10 | void formatBillingRecord(BillingRecord billingRecord); 11 | 12 | void journalBillingRecord(BillingRecord billingRecord); 13 | 14 | void processBillingRecord(BillingRecord billingRecord); 15 | 16 | void processCorporateBillingRecord(BillingRecord billingRecord); 17 | 18 | void processCustomerSpecificBillingRecord(BillingRecord billingRecord); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/anair/billing/service/BillingServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.anair.billing.service; 2 | 3 | import org.anair.billing.model.BillingRecord; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | public class BillingServiceImpl implements BillingService { 8 | private static final Logger LOG = LoggerFactory.getLogger(BillingServiceImpl.class); 9 | 10 | @Override 11 | public void processBillingRecord(BillingRecord billingRecord) { 12 | for(long l=0;l { 8 | 9 | @Override 10 | public DataStream newInstance() { 11 | return new DataStream(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/eventprocessor/FormatDataStreamEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.eventprocessor; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.anair.datastream.service.DatastreamService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class FormatDataStreamEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(FormatDataStreamEventProcessor.class); 14 | private DatastreamService dataStreamService; 15 | 16 | @Override 17 | public void onEvent(DataStream dataStream, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, dataStream.toString()); 20 | dataStreamService.formatDatastream(dataStream); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, dataStream.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setDataStreamService(DatastreamService dataStreamService) { 28 | this.dataStreamService = dataStreamService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/eventprocessor/JournalDataStreamEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.eventprocessor; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.anair.datastream.service.DatastreamService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class JournalDataStreamEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(JournalDataStreamEventProcessor.class); 14 | private DatastreamService dataStreamService; 15 | 16 | @Override 17 | public void onEvent(DataStream dataStream, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, dataStream.toString()); 20 | dataStreamService.journalDatastream(dataStream); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, dataStream.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setDataStreamService(DatastreamService dataStreamService) { 28 | this.dataStreamService = dataStreamService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/eventprocessor/ProcessADataStreamEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.eventprocessor; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.anair.datastream.service.DatastreamService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class ProcessADataStreamEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(ProcessADataStreamEventProcessor.class); 14 | private DatastreamService dataStreamService; 15 | 16 | @Override 17 | public void onEvent(DataStream dataStream, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, dataStream.toString()); 20 | dataStreamService.processDatastream_A(dataStream); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, dataStream.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setDataStreamService(DatastreamService dataStreamService) { 28 | this.dataStreamService = dataStreamService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/eventprocessor/ProcessBDataStreamEventProcessor.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.eventprocessor; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.anair.datastream.service.DatastreamService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | import com.lmax.disruptor.EventHandler; 10 | 11 | public class ProcessBDataStreamEventProcessor implements EventHandler { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(ProcessBDataStreamEventProcessor.class); 14 | private DatastreamService dataStreamService; 15 | 16 | @Override 17 | public void onEvent(DataStream dataStream, long sequence, boolean endOfBatch) 18 | throws Exception { 19 | LOG.trace("Sequence: {}. Going to process {}",sequence, dataStream.toString()); 20 | dataStreamService.processDatastream_B(dataStream); 21 | if(sequence%10==0){ 22 | LOG.info("Sequence: {}. {}",sequence, dataStream.toString()); 23 | } 24 | } 25 | 26 | @Required 27 | public void setDataStreamService(DatastreamService dataStreamService) { 28 | this.dataStreamService = dataStreamService; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/eventtranslator/DataStreamEventTranslator.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.eventtranslator; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import com.lmax.disruptor.EventTranslator; 8 | 9 | public class DataStreamEventTranslator implements EventTranslator{ 10 | 11 | private static final Logger LOG = LoggerFactory.getLogger(DataStreamEventTranslator.class); 12 | private DataStream dataStream; 13 | 14 | public DataStreamEventTranslator(DataStream dataStream) { 15 | this.dataStream = dataStream; 16 | } 17 | 18 | @Override 19 | public void translateTo(DataStream dataStream, long sequence) { 20 | dataStream.setDataStreamId(this.dataStream.getDataStreamId()); 21 | dataStream.setDataStreamType(this.dataStream.getDataStreamType()); 22 | dataStream.setDataStream(this.dataStream.getDataStream()); 23 | dataStream.setDataSource(this.dataStream.getDataSource()); 24 | dataStream.setDataTarget(this.dataStream.getDataTarget()); 25 | 26 | if(sequence%10==0){ 27 | LOG.info("Published {} to sequence: {}",dataStream.toString(), sequence); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/disruptor/publisher/DataStreamEventPublisher.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.disruptor.publisher; 2 | 3 | import org.anair.datastream.disruptor.eventtranslator.DataStreamEventTranslator; 4 | import org.anair.datastream.model.DataStream; 5 | import org.anair.disruptor.DisruptorConfig; 6 | import org.anair.disruptor.publisher.EventPublisher; 7 | 8 | public class DataStreamEventPublisher implements EventPublisher{ 9 | 10 | private DisruptorConfig disruptorConfig; 11 | 12 | @Override 13 | public void publish(DataStream dataStream){ 14 | disruptorConfig.publish(new DataStreamEventTranslator(dataStream)); 15 | } 16 | 17 | @Override 18 | public void setDisruptorConfig(DisruptorConfig disruptorConfig) { 19 | this.disruptorConfig = disruptorConfig; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/message/listener/DataStreamMessageListener.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.message.listener; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | import org.anair.disruptor.publisher.EventPublisher; 5 | import org.apache.commons.lang3.StringUtils; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class DataStreamMessageListener { 10 | private static final Logger LOG = LoggerFactory.getLogger(DataStreamMessageListener.class); 11 | 12 | private EventPublisher dataStreamEventPublisher; 13 | 14 | public void inMessage(String number){ 15 | if(StringUtils.isBlank(number) || !StringUtils.isNumeric(number.trim())){ 16 | LOG.error("Enter a valid long number"); 17 | return; 18 | } 19 | long inboundMessageCount = Long.parseLong(number.trim()); 20 | for(long l=0;l dataStreamEventPublisher) { 38 | this.dataStreamEventPublisher = dataStreamEventPublisher; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/model/DataStream.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class DataStream implements Serializable { 6 | 7 | private static final long serialVersionUID = -5915976976824831395L; 8 | 9 | private long dataStreamId; 10 | private String dataStreamType; 11 | private String dataStream; 12 | private String dataSource; 13 | private String dataTarget; 14 | public long getDataStreamId() { 15 | return dataStreamId; 16 | } 17 | public void setDataStreamId(long dataStreamId) { 18 | this.dataStreamId = dataStreamId; 19 | } 20 | public String getDataStreamType() { 21 | return dataStreamType; 22 | } 23 | public void setDataStreamType(String dataStreamType) { 24 | this.dataStreamType = dataStreamType; 25 | } 26 | public String getDataStream() { 27 | return dataStream; 28 | } 29 | public void setDataStream(String dataStream) { 30 | this.dataStream = dataStream; 31 | } 32 | public String getDataSource() { 33 | return dataSource; 34 | } 35 | public void setDataSource(String dataSource) { 36 | this.dataSource = dataSource; 37 | } 38 | public String getDataTarget() { 39 | return dataTarget; 40 | } 41 | public void setDataTarget(String dataTarget) { 42 | this.dataTarget = dataTarget; 43 | } 44 | @Override 45 | public String toString() { 46 | return "DataStreamId [" + dataStreamId + "]"; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/service/DatastreamService.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.service; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | 5 | public interface DatastreamService { 6 | static final long delay = 555555L; 7 | 8 | void journalDatastream(DataStream dataStream); 9 | 10 | void processDatastream_A(DataStream dataStream); 11 | 12 | void processDatastream_B(DataStream dataStream); 13 | 14 | DataStream formatDatastream(DataStream dataStream); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/anair/datastream/service/DatastreamServiceImpl.java: -------------------------------------------------------------------------------- 1 | package org.anair.datastream.service; 2 | 3 | import org.anair.datastream.model.DataStream; 4 | 5 | public class DatastreamServiceImpl implements DatastreamService { 6 | 7 | @Override 8 | public void journalDatastream(DataStream dataStream) { 9 | for(long l=0;l 2 | 5 | 6 | 16 | 17 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | 69 | 70 | 73 | 74 | 77 | 78 | 81 | 82 | 85 | 86 | 87 | 88 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/resources/spring-datastream-disruptor.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | 65 | 66 | 69 | 70 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/resources/spring-jms.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 15 | 16 | 20 | 21 | 24 | 25 | 26 | 27 | 33 | 34 | 38 | 39 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/resources/spring-jmx.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/resources/spring-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 10 | 11 | 13 | 14 | 15 | --------------------------------------------------------------------------------