├── .gitignore ├── README.md └── spring-batch-scalability ├── etc ├── ffmq │ └── conf │ │ ├── ffmq-server.properties │ │ ├── templates.mapping │ │ └── templates │ │ ├── queueTemplate-DEFAULT.properties │ │ └── queueTemplate-TEMP.properties └── jetty-env.xml ├── pom.xml ├── repo ├── javax │ └── jms │ │ └── jms │ │ ├── 1.1 │ │ ├── jms-1.1.jar │ │ ├── jms-1.1.jar.md5 │ │ ├── jms-1.1.jar.sha1 │ │ ├── jms-1.1.pom │ │ ├── jms-1.1.pom.md5 │ │ └── jms-1.1.pom.sha1 │ │ ├── maven-metadata-local.xml │ │ ├── maven-metadata-local.xml.md5 │ │ └── maven-metadata-local.xml.sha1 ├── net │ └── timewalker │ │ └── ffmq │ │ ├── ffmq3-core │ │ ├── 3.0.5 │ │ │ ├── ffmq3-core-3.0.5.jar │ │ │ ├── ffmq3-core-3.0.5.jar.md5 │ │ │ ├── ffmq3-core-3.0.5.jar.sha1 │ │ │ ├── ffmq3-core-3.0.5.pom │ │ │ ├── ffmq3-core-3.0.5.pom.md5 │ │ │ └── ffmq3-core-3.0.5.pom.sha1 │ │ ├── maven-metadata-local.xml │ │ ├── maven-metadata-local.xml.md5 │ │ └── maven-metadata-local.xml.sha1 │ │ ├── ffmq3-server │ │ ├── 3.0.5 │ │ │ ├── ffmq3-server-3.0.5.jar │ │ │ ├── ffmq3-server-3.0.5.jar.md5 │ │ │ ├── ffmq3-server-3.0.5.jar.sha1 │ │ │ ├── ffmq3-server-3.0.5.pom │ │ │ ├── ffmq3-server-3.0.5.pom.md5 │ │ │ └── ffmq3-server-3.0.5.pom.sha1 │ │ ├── maven-metadata-local.xml │ │ ├── maven-metadata-local.xml.md5 │ │ └── maven-metadata-local.xml.sha1 │ │ └── ffmq3 │ │ ├── 3.0.5 │ │ ├── ffmq3-3.0.5.pom │ │ ├── ffmq3-3.0.5.pom.md5 │ │ └── ffmq3-3.0.5.pom.sha1 │ │ ├── maven-metadata-local.xml │ │ ├── maven-metadata-local.xml.md5 │ │ └── maven-metadata-local.xml.sha1 └── uk │ └── ac │ └── shef │ └── wit │ └── simmetrics │ ├── 1.6.2 │ ├── simmetrics-1.6.2.jar │ ├── simmetrics-1.6.2.jar.md5 │ ├── simmetrics-1.6.2.jar.sha1 │ ├── simmetrics-1.6.2.pom │ ├── simmetrics-1.6.2.pom.md5 │ └── simmetrics-1.6.2.pom.sha1 │ ├── maven-metadata.xml │ ├── maven-metadata.xml.md5 │ └── maven-metadata.xml.sha1 └── src ├── main ├── java │ └── com │ │ └── ontheserverside │ │ └── batch │ │ └── bank │ │ ├── controller │ │ └── RootController.java │ │ ├── processing │ │ ├── Elixir0Mapper.java │ │ ├── JobParameterExecutionDecider.java │ │ ├── ModuloPartitioner.java │ │ └── SynchronizedItemReaderDecorator.java │ │ ├── screening │ │ ├── FuzzyMatcher.java │ │ ├── JaroBagFuzzyMatcher.java │ │ ├── SDNEntity.java │ │ ├── SanctionMatch.java │ │ ├── SanctionScreeningContext.java │ │ ├── SanctionScreeningProcessor.java │ │ ├── SanctionScreeningRecoveryCleaner.java │ │ └── UpdateScreenedTransactionStatusTasklet.java │ │ └── tx │ │ ├── Elixir0Generator.java │ │ ├── Elixir0Transaction.java │ │ ├── SimpleElixir0Generator.java │ │ └── TransactionStatus.java ├── resources │ ├── META-INF │ │ ├── database │ │ │ ├── init.sql │ │ │ ├── sdn_addresses.csv │ │ │ ├── sdn_alternate_names.csv │ │ │ └── sdn_names.csv │ │ └── spring │ │ │ ├── applicationContext.xml │ │ │ ├── batchContext.xml │ │ │ ├── elixir0ImportJob.xml │ │ │ ├── hibernateContext.xml │ │ │ └── jmsContext.xml │ ├── addresses.txt │ ├── dictionary.txt │ ├── log4j.properties │ └── names.txt └── webapp │ └── WEB-INF │ ├── spring │ └── webmvc-config.xml │ ├── views │ └── home.jsp │ └── web.xml └── test ├── java └── com │ └── ontheserverside │ └── batch │ └── bank │ ├── job │ └── Elixir0LoadStepTest.java │ ├── processing │ ├── JobParameterExecutionDeciderTest.java │ └── ModuloPartitionerTest.java │ └── screening │ ├── JaroBagFuzzyMatcherTest.java │ └── SanctionScreeningProcessorTest.java └── resources └── elixir0 └── 5Tx.elixir0 /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | #IntelliJ files 4 | .idea 5 | .DS_store 6 | *.iml 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spring Batch scaling strategies - sample application 2 | === 3 | http://www.ontheserverside.com/blog/2014/07/23/horizontal-and-vertical-scaling-strategies-for-batch-applications/ 4 | 5 | This is sample application developed for ["Horizontal and Vertical Scaling Strategies for Batch Applications"](http://www.ontheserverside.com/blog/2014/07/23/horizontal-and-vertical-scaling-strategies-for-batch-applications/) article. 6 | 7 | Application is responsible for processing Elixir0 messages. Elixir0 is a country-domestic Polish bank message format that represents standard credit transfer transactions. All payments contained by Elixir0 are screened against OFAC's Specially Designated Nationals List. Screening algorithm performs fuzzy matching of beneficiary and ordering party name, address and alternate name against every SDN entity. If algorithm detects that sanctions might be imposed on ordering or receiving party, placement of the particular transaction is suspended and waits for manual approval. 8 | 9 | Please bear in mind that the implementation of payment sanction screening mechanism used here is not the most optimal and performant algorithm for this task. Also, it should not be considered as a complete solution. 10 | 11 | ## How to run 12 | 13 | Application is using Maven as a dependency management system, so all required libraries should be downloaded automatically. FFMQ is used as a JMS broker, Jetty is used as a web container and H2 running in in-memory mode is used as a database. All these services are configured automatically and no action from user is required to set them up. 14 | 15 | ``` 16 | $ git clone git@github.com:pdyraga/spring-batch-samples.git 17 | $ cd spring-batch-samples/spring-batch-scalability/ 18 | $ mvn clean jetty:run 19 | ``` 20 | 21 | 22 | ## How to use 23 | 24 | Go to [http://localhost:8080](http://localhost:8080) and generate sample Elixir0 message first. To do so, please enter number of transactions that the generated file should contain (e.g. `500`) and desired location of the output file (e.g. `/tmp/elixir0.500`). Next, please click on `Generate` and wait for Elixir0 file to be created. When file generation process is complete, you should see `Elixir0 message created` information. Also, input file path is automatically filled with location of file that has just been created. In the menu drop down next to the input file location you can choose scaling strategy that should be used for performing payment sanctions screening. After choosing some scaling strategy, please click on `Run job` button and the import process should start immediately: 25 | 26 | ![image](https://cloud.githubusercontent.com/assets/4712360/3423638/cddb7082-ffa1-11e3-975e-af98ea53980e.png) 27 | 28 | You can access database web interface by going to [http://localhost:8082](http://localhost:8082). The username is `sa` and password is `sa`. The most important job outcome is list of transactions that have been suspended together with sanctions matched for particular transaction. You can observe this list by querying the `SANCTION_PREVIEW` view: `SELECT * FROM SANCTION_PREVIEW `. Each row in this view represents suspended transaction. View displays all data from Elixir0 transactions that were analysed by fuzzy string matching algorithm, that is, beneficiary name, beneficiary address, ordering party name and ordering party address. Columns starting with `SDN_` prefix are data from entity on the OFAC's SDN list that could be potentially involved in the particular transaction. For instance, the first row represents transaction that has been suspended because the beneficiary name (`MOLDTRANSAVIA SRL`) is matching SDN entity with the same name. 29 | 30 | Please visit the article for more information: http://www.ontheserverside.com/blog/2014/07/23/horizontal-and-vertical-scaling-strategies-for-batch-applications/ 31 | 32 | ![image](https://cloud.githubusercontent.com/assets/4712360/3423640/d5b10236-ffa1-11e3-9c54-93a11beb55e9.png) 33 | -------------------------------------------------------------------------------- /spring-batch-scalability/etc/ffmq/conf/ffmq-server.properties: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------# 2 | # FFMQ Server settings # 3 | #---------------------------------------------------------------# 4 | 5 | #--------------------------------# 6 | # Management # 7 | #--------------------------------# 8 | 9 | # Destination definitions folder 10 | #-------------------------------- 11 | # - Folder where to store/lookup destinations XML descriptors (can be relative) 12 | management.destinationDefinitions.directory=${FFMQ_WORKING_DIR}/destinations 13 | 14 | # Bridge definitions folder 15 | #-------------------------------- 16 | # - Folder where to look for bridge definitions XML descriptors (can be relative) 17 | #management.bridgeDefinitions.directory=${FFMQ_BASE}/bridges 18 | 19 | # Templates folder 20 | #------------------ 21 | # - Folder where to look for templates descriptors (can be relative) 22 | management.templates.directory=${FFMQ_BASE}/conf/templates 23 | 24 | # Templates mapping file 25 | #------------------------ 26 | # - Path to the templates mapping file (can be relative) 27 | management.templates.mapping=${FFMQ_BASE}/conf/templates.mapping 28 | 29 | # Queues auto-creation 30 | #---------------------- 31 | # - true : accessing an unknown queue will auto-create it if a corresponding 32 | # mapping exist in the templates mapping file 33 | # - false : accessing an unknown queue will throw a JMSException 34 | management.autoCreate.queues=true 35 | 36 | # Topics auto-creation 37 | #---------------------- 38 | # - true : accessing an unknown topic will auto-create it if a corresponding 39 | # mapping exist in the templates mapping file 40 | # - false : accessing an unknown topic will throw a JMSException 41 | management.autoCreate.topics=true 42 | 43 | # Queues auto-deployment on startup 44 | #----------------------------------- 45 | # - true : the server will try to deploy all existing queues on startup 46 | # - false : queues are only deployed on first use 47 | management.deployOnStartup.queues=true 48 | 49 | # Topics auto-deployment on startup 50 | #----------------------------------- 51 | # - true : the server will try to deploy all existing topics on startup 52 | # - false : topics are only deployed on first use 53 | management.deployOnStartup.topics=true 54 | 55 | # Remote administration 56 | #----------------------- 57 | # - true : allows remote administration of the server through admin queues 58 | # (this is usually done through the ffmq-admin-client utility) 59 | # - false : disable the remote administration feature 60 | management.remoteAdmin.enabled=true 61 | 62 | # Default data directory 63 | #------------------------ 64 | # - Folder to use as a data folder for destinations created through remote administration (can be relative) 65 | management.defaultData.directory=${FFMQ_WORKING_DIR}/data 66 | 67 | # JMX support 68 | #------------- 69 | # - true : start a JMX agent on server startup 70 | # - false : disable the JMX agent 71 | management.jmx.agent.enabled=true 72 | # RMI port to use for the agent registry 73 | management.jmx.agent.jndi.rmi.port=10003 74 | # RMI address to use for the agent registry (supports address auto-discovery using 'auto:eth0' for example) 75 | management.jmx.agent.rmi.listenAddr=0.0.0.0 76 | 77 | #--------------------------------# 78 | # Listeners # 79 | #--------------------------------# 80 | # Note : right now, there is only one available listener 81 | # using TCP sockets 82 | 83 | # General 84 | #-------- 85 | # Time to wait for credentials before dropping the client (in seconds) 86 | listener.auth.timeout=5 87 | 88 | # TCP listener 89 | #-------------- 90 | # - If enabled, the TCP listener will start on server startup 91 | # - You can set the listen address,port and backlog for the listen socket 92 | # (supports address auto-discovery using 'auto:eth0' for example) 93 | listener.tcp.enabled=true 94 | listener.tcp.useNIO=false 95 | listener.tcp.listenAddr=0.0.0.0 96 | listener.tcp.listenPort=10002 97 | listener.tcp.backLog=50 98 | listener.tcp.capacity=200 99 | 100 | # TCP transport settings 101 | #------------------------ 102 | transport.tcp.pingInterval=30 103 | transport.tcp.sendQueueMaxSize=1000 104 | transport.tcp.packet.maxSize=1049600 105 | transport.tcp.stream.sendBufferSize=8192 106 | transport.tcp.stream.recvBufferSize=8192 107 | transport.tcp.initialPacketBufferSize=4096 108 | transport.tcp.socket.sendBufferSize=65536 109 | transport.tcp.socket.recvBufferSize=65536 110 | # SSL support (server-side) 111 | transport.tcp.ssl.enabled=false 112 | transport.tcp.ssl.protocol=SSLv3 113 | transport.tcp.ssl.keyManager.algorithm=SunX509 114 | transport.tcp.ssl.keyStore.type=JKS 115 | transport.tcp.ssl.keyStore.path=${FFMQ_BASE}/conf/server-keystore.jks 116 | transport.tcp.ssl.keyStore.password=ffmqpass 117 | transport.tcp.ssl.keyStore.keyPassword=ffmqpass 118 | 119 | #--------------------------------# 120 | # Security # 121 | #--------------------------------# 122 | 123 | # Global security switch 124 | #------------------------ 125 | # - true : enable security checks (you also need to have a valid connector and configuration) 126 | # - false : disable security globally 127 | security.enabled=false 128 | 129 | # Security connector implementation 130 | #----------------------------------- 131 | # - Fully qualified class name of the security connector to use 132 | # Note : right now, there is only one available connector implementation 133 | # using an XML descriptor (net.timewalker.ffmq3.security.XMLSecurityConnector) 134 | security.connector=net.timewalker.ffmq3.security.XMLSecurityConnector 135 | 136 | # XML Security connector configuration file 137 | #------------------------------------------- 138 | # - Path to the XML configuration file for the XML security connector 139 | security.connector.xml.securityFile=${FFMQ_BASE}/conf/security.xml 140 | 141 | #--------------------------------# 142 | # Internal tuning # 143 | #--------------------------------# 144 | 145 | # Asynchronous task manager - Delivery 146 | # - Pool min size (ie. how many threads to create on startup) 147 | asyncTaskManager.notification.threadPool.minSize=5 148 | # - Pool max idle (ie. how many unused threads to keep ready in the pool) 149 | asyncTaskManager.notification.threadPool.maxIdle=10 150 | # - Pool max size (ie. how many threads should we allocate at most) 151 | asyncTaskManager.notification.threadPool.maxSize=15 152 | 153 | # Asynchronous task manager - Delivery 154 | # - Pool min size (ie. how many threads to create on startup) 155 | asyncTaskManager.delivery.threadPool.minSize=0 156 | # - Pool max idle (ie. how many unused threads to keep ready in the pool) 157 | asyncTaskManager.delivery.threadPool.maxIdle=5 158 | # - Pool max size (ie. how many threads should we allocate at most) 159 | asyncTaskManager.delivery.threadPool.maxSize=10 160 | 161 | # Asynchronous task manager - Disk I/O 162 | # - Pool min size (ie. how many threads to create on startup) 163 | asyncTaskManager.diskIO.threadPool.minSize=1 164 | # - Pool max idle (ie. how many unused threads to keep ready in the pool) 165 | asyncTaskManager.diskIO.threadPool.maxIdle=2 166 | # - Pool max size (ie. how many threads should we allocate at most) 167 | asyncTaskManager.diskIO.threadPool.maxSize=4 168 | 169 | # Consumer message prefetching 170 | consumer.prefetch.size=10 171 | 172 | # Redelivery delay (in milliseconds) 173 | # - If positive, delay message availability in queue after a rollback 174 | delivery.redeliveryDelay=0 175 | 176 | 177 | #--------------------------------# 178 | # Logging # 179 | #--------------------------------# 180 | 181 | # Loggers definitions 182 | log4j.logger.net.timewalker.ffmq3=INFO,logFile 183 | log4j.additivity.net.timewalker.ffmq3=false 184 | 185 | # JMX logging 186 | log4j.logger.javax.management=INFO,logFile 187 | log4j.additivity.javax.management=false 188 | 189 | # Appenders definitions 190 | log4j.appender.console=org.apache.log4j.ConsoleAppender 191 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 192 | log4j.appender.console.layout.ConversionPattern=[%5p] %m%n 193 | -------------------------------------------------------------------------------- /spring-batch-scalability/etc/ffmq/conf/templates.mapping: -------------------------------------------------------------------------------- 1 | queue:TEMP-QUEUE-*:TEMP_QUEUE_TEMPLATE 2 | queue:*:DEFAULT_QUEUE_TEMPLATE 3 | -------------------------------------------------------------------------------- /spring-batch-scalability/etc/ffmq/conf/templates/queueTemplate-DEFAULT.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This is the default template for queues 3 | # 4 | name = DEFAULT_QUEUE_TEMPLATE 5 | 6 | persistentStore.initialBlockCount = 1000 7 | persistentStore.autoExtendAmount = 1000 8 | persistentStore.maxBlockCount = 10000 9 | persistentStore.blockSize = 4096 10 | persistentStore.dataFolder = ${FFMQ_WORKING_DIR}/data 11 | persistentStore.useJournal = true 12 | persistentStore.syncMethod = 2 13 | 14 | persistentStore.journal.preAllocateFiles=false 15 | 16 | memoryStore.maxMessages = 1000 17 | memoryStore.overflowToPersistent = false 18 | -------------------------------------------------------------------------------- /spring-batch-scalability/etc/ffmq/conf/templates/queueTemplate-TEMP.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This is the default template for temporary queues 3 | # 4 | name = TEMP_QUEUE_TEMPLATE 5 | 6 | persistentStore.initialBlockCount = 100 7 | persistentStore.autoExtendAmount = 100 8 | persistentStore.maxBlockCount = 1000 9 | persistentStore.blockSize = 4096 10 | persistentStore.dataFolder = ${FFMQ_WORKING_DIR}/data 11 | persistentStore.useJournal = false 12 | 13 | memoryStore.maxMessages = 1000 14 | -------------------------------------------------------------------------------- /spring-batch-scalability/etc/jetty-env.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jdbc/DS 6 | 7 | 8 | jdbc:h2:mem:bank;DB_CLOSE_DELAY=-1 9 | sa 10 | sa 11 | 12 | 13 | 14 | 15 | ffmq 16 | etc/ffmq/conf/ffmq-server.properties 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /spring-batch-scalability/pom.xml: -------------------------------------------------------------------------------- 1 | 5 | 4.0.0 6 | 7 | com.ontheserverside.batch 8 | spring-batch-scalability 9 | 1.0 10 | war 11 | 12 | Spring Batch scalability samples 13 | 14 | 15 | 1.7 16 | 1.7 17 | UTF-8 18 | 19 | 4.0.0.RELEASE 20 | 2.2.3.RELEASE 21 | 1.3.0.M1 22 | 3.0.1.RELEASE 23 | 4.3.0.Final 24 | 9.1.1.v20140108 25 | 1.3.175 26 | 3.0.5 27 | 28 | etc/ffmq 29 | target/ffmq-data 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-antrun-plugin 37 | 38 | 39 | setUpFFMQDataDirectories 40 | generate-sources 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | run 50 | 51 | 52 | 53 | 54 | 55 | org.eclipse.jetty 56 | jetty-maven-plugin 57 | ${org.eclipse.jetty.version} 58 | 59 | 60 | 61 | FFMQ_BASE 62 | ${net.timewalker.ffmq.dir.config} 63 | 64 | 65 | FFMQ_WORKING_DIR 66 | ${net.timewalker.ffmq.dir.working} 67 | 68 | 69 | 70 | etc/jetty-env.xml 71 | 72 | 73 | 74 | 75 | com.h2database 76 | h2 77 | ${com.h2database.version} 78 | 79 | 80 | net.timewalker.ffmq 81 | ffmq3-server 82 | ${net.timewalker.ffmq.version} 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.springframework 92 | spring-context 93 | ${org.springframework.version} 94 | 95 | 96 | org.springframework.batch 97 | spring-batch-core 98 | ${org.springframework.batch.version} 99 | 100 | 101 | org.springframework.batch 102 | spring-batch-integration 103 | ${org.springframework.batch.integration.version} 104 | 105 | 106 | org.springframework.integration 107 | spring-integration-core 108 | 109 | 110 | 111 | 112 | org.springframework.integration 113 | spring-integration-jms 114 | ${org.springframework.integration.version} 115 | 116 | 117 | org.springframework 118 | spring-orm 119 | ${org.springframework.version} 120 | 121 | 122 | org.springframework 123 | spring-webmvc 124 | ${org.springframework.version} 125 | 126 | 127 | org.hibernate 128 | hibernate-core 129 | ${org.hibernate.version} 130 | 131 | 132 | org.apache.commons 133 | commons-lang3 134 | 3.1 135 | 136 | 137 | uk.ac.shef.wit 138 | simmetrics 139 | 1.6.2 140 | 141 | 142 | net.timewalker.ffmq 143 | ffmq3-core 144 | ${net.timewalker.ffmq.version} 145 | 146 | 147 | 148 | 149 | junit 150 | junit 151 | 4.11 152 | test 153 | 154 | 155 | org.easymock 156 | easymock 157 | 3.2 158 | test 159 | 160 | 161 | org.springframework 162 | spring-test 163 | ${org.springframework.version} 164 | test 165 | 166 | 167 | org.springframework.batch 168 | spring-batch-test 169 | ${org.springframework.batch.version} 170 | test 171 | 172 | 173 | com.h2database 174 | h2 175 | ${com.h2database.version} 176 | test 177 | 178 | 179 | 180 | 181 | 182 | project.local 183 | project 184 | file:${project.basedir}/repo 185 | 186 | 187 | spring.release 188 | spring release 189 | http://maven.springframework.org/release/ 190 | 191 | 192 | 193 | 194 | 195 | 196 | never 197 | 198 | 199 | false 200 | 201 | project.local 202 | project 203 | file:${project.basedir}/repo 204 | 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdyraga/spring-batch-samples/2cbe2caf03954a2899cc8d0bab079e292df39cb9/spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.jar -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.jar.md5: -------------------------------------------------------------------------------- 1 | ad558b2376ce94b91bb72d67b30a4f05 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.jar.sha1: -------------------------------------------------------------------------------- 1 | 5e106d07e523fb6d40cf086b9b413268f6302f26 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.pom: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | javax.jms 4 | jms 5 | 1.1 6 | Java Message Service 7 | 8 | The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java 2 Platform, Enterprise Edition (J2EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous. 9 | 10 | http://java.sun.com/products/jms 11 | 12 | http://java.sun.com/products/jms/docs.html 13 | 14 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.pom.md5: -------------------------------------------------------------------------------- 1 | 479233e944488d328423f24e67626b85 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/1.1/jms-1.1.pom.sha1: -------------------------------------------------------------------------------- 1 | 27a2e84f6118a2bbd0266edd9d53870528473f92 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | javax.jms 4 | jms 5 | 6 | 1.1 7 | 8 | 1.1 9 | 10 | 20140309121905 11 | 12 | 13 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/maven-metadata-local.xml.md5: -------------------------------------------------------------------------------- 1 | 81a55a5edb7c5df00d0bf9b1b5322b3f -------------------------------------------------------------------------------- /spring-batch-scalability/repo/javax/jms/jms/maven-metadata-local.xml.sha1: -------------------------------------------------------------------------------- 1 | 253655e6932da154607206f38f7325403b169d02 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdyraga/spring-batch-samples/2cbe2caf03954a2899cc8d0bab079e292df39cb9/spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.jar -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.jar.md5: -------------------------------------------------------------------------------- 1 | d19d3b2789b7d5ae2c381aafa6b188fc -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.jar.sha1: -------------------------------------------------------------------------------- 1 | 80c26745470ff9e962b7209c48ea6fe43f467861 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.pom: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | net.timewalker.ffmq 6 | ffmq3-core 7 | jar 8 | 3.0.5 9 | FFMQ Core 10 | FFMQ Core module 11 | 12 | 13 | net.timewalker.ffmq 14 | ffmq3 15 | 3.0.5 16 | 17 | 18 | 19 | 20 | 21 | src/main/resources 22 | true 23 | 24 | 25 | 26 | 27 | 28 | org.apache.maven.plugins 29 | maven-compiler-plugin 30 | 31 | 1.4 32 | 1.4 33 | 34 | 35 | 36 | org.apache.maven.plugins 37 | maven-surefire-plugin 38 | 39 | true 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-eclipse-plugin 45 | 46 | 47 | temp/classes 48 | 49 | 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-jar-plugin 54 | 55 | 56 | 57 | 58 | ${pom.name} 59 | 60 | 61 | ${pom.version} 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 80 | 81 | 82 | 83 | commons-logging 84 | commons-logging 85 | compile 86 | 87 | 88 | avalon-framework 89 | avalon-framework 90 | 91 | 92 | javax.servlet 93 | servlet-api 94 | 95 | 96 | logkit 97 | logkit 98 | 99 | 100 | 101 | 102 | log4j 103 | log4j 104 | compile 105 | 106 | 107 | com.sun.jdmk 108 | jmxtools 109 | 110 | 111 | com.sun.jmx 112 | jmxri 113 | 114 | 115 | javax.activation 116 | activation 117 | 118 | 119 | javax.mail 120 | mail 121 | 122 | 123 | 124 | 125 | javax.jms 126 | jms 127 | compile 128 | 129 | 130 | mx4j 131 | mx4j 132 | compile 133 | 134 | 135 | mx4j 136 | mx4j-remote 137 | compile 138 | 139 | 140 | junit 141 | junit 142 | test 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.pom.md5: -------------------------------------------------------------------------------- 1 | 8c0c56f799f27df3bd955cb25824d0ec -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/3.0.5/ffmq3-core-3.0.5.pom.sha1: -------------------------------------------------------------------------------- 1 | 91d60bd6dcd7a081b96c0d11c289fb95d0b19ce4 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | net.timewalker.ffmq3 4 | ffmq3-core 5 | 6 | 3.0.5 7 | 8 | 3.0.5 9 | 10 | 20140309122341 11 | 12 | 13 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/maven-metadata-local.xml.md5: -------------------------------------------------------------------------------- 1 | c48dd932ffd057ea047b74c0fd5be7f4 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-core/maven-metadata-local.xml.sha1: -------------------------------------------------------------------------------- 1 | b40e215c5e0906000d73d36dee383215613eb05a -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdyraga/spring-batch-samples/2cbe2caf03954a2899cc8d0bab079e292df39cb9/spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.jar -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.jar.md5: -------------------------------------------------------------------------------- 1 | 45edca610e4c16300091326f224ae8b0 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.jar.sha1: -------------------------------------------------------------------------------- 1 | 24eef0822f877290e3626c3d27ccd78ce21a5a1a -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.pom: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | net.timewalker.ffmq 6 | ffmq3-server 7 | jar 8 | 3.0.5 9 | FFMQ Server 10 | FFMQ Server module 11 | 12 | 13 | net.timewalker.ffmq 14 | ffmq3 15 | 3.0.5 16 | 17 | 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-compiler-plugin 23 | 24 | 1.4 25 | 1.4 26 | 27 | 28 | 29 | org.apache.maven.plugins 30 | maven-surefire-plugin 31 | 32 | true 33 | runtime/bin 34 | 35 | 36 | 37 | org.apache.maven.plugins 38 | maven-eclipse-plugin 39 | 40 | 41 | temp/classes 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-jar-plugin 48 | 49 | 50 | 51 | ${pom.name} 52 | ${pom.version} 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | net.timewalker.ffmq 63 | ffmq3-core 64 | 3.0.5 65 | 66 | 67 | junit 68 | junit 69 | test 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.pom.md5: -------------------------------------------------------------------------------- 1 | 54e9e7218e0829fa2e60758eb64b4dae -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/3.0.5/ffmq3-server-3.0.5.pom.sha1: -------------------------------------------------------------------------------- 1 | c38295dea9985bfd1668d55ebf42d6e6f011f000 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | net.timewalker.ffmq3 4 | ffmq3-server 5 | 6 | 3.0.5 7 | 8 | 3.0.5 9 | 10 | 20140309122632 11 | 12 | 13 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/maven-metadata-local.xml.md5: -------------------------------------------------------------------------------- 1 | daa060829c8434551ef657a35ac50461 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3-server/maven-metadata-local.xml.sha1: -------------------------------------------------------------------------------- 1 | 0eea2a8edd6a29ca0dda02c81e70f0bf3f1ae8ca -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/3.0.5/ffmq3-3.0.5.pom: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.timewalker.ffmq 5 | ffmq3 6 | pom 7 | 3.0.5 8 | FFMQ 9 | http://www.timewalker.net/ffmq 10 | 11 | 12 | core 13 | server 14 | tools 15 | distribution 16 | 17 | 18 | 19 | 20 | 21 | commons-logging 22 | commons-logging 23 | 1.1 24 | 25 | 26 | log4j 27 | log4j 28 | 1.2.15 29 | 30 | 31 | javax.jms 32 | jms 33 | 1.1 34 | 35 | 36 | mx4j 37 | mx4j 38 | 3.0.2 39 | 40 | 41 | mx4j 42 | mx4j-remote 43 | 3.0.2 44 | 45 | 46 | junit 47 | junit 48 | 3.8.1 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/3.0.5/ffmq3-3.0.5.pom.md5: -------------------------------------------------------------------------------- 1 | 9db0dc1eb566063e51f9629dc17b8043 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/3.0.5/ffmq3-3.0.5.pom.sha1: -------------------------------------------------------------------------------- 1 | 995bfc4e1701662f4b6060877353ae8318748b5b -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | net.timewalker.ffmq3 4 | ffmq3 5 | 6 | 3.0.5 7 | 8 | 3.0.5 9 | 10 | 20140309122205 11 | 12 | 13 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/maven-metadata-local.xml.md5: -------------------------------------------------------------------------------- 1 | 20651b001a9e6a0d77d6ff4535b6a030 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/net/timewalker/ffmq/ffmq3/maven-metadata-local.xml.sha1: -------------------------------------------------------------------------------- 1 | 329e36919c1f99e09c86b040cf35e59106f916c1 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pdyraga/spring-batch-samples/2cbe2caf03954a2899cc8d0bab079e292df39cb9/spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.jar -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.jar.md5: -------------------------------------------------------------------------------- 1 | d730f0b5e5b0b18a2931227b8d3e3820 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.jar.sha1: -------------------------------------------------------------------------------- 1 | 546cfaf6de50dbdd53b35735567f456c37036113 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | uk.ac.shef.wit 6 | simmetrics 7 | 1.6.2 8 | 9 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.pom.md5: -------------------------------------------------------------------------------- 1 | e66c9ab9437bb1ec06d1c5ff0612e50f -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/1.6.2/simmetrics-1.6.2.pom.sha1: -------------------------------------------------------------------------------- 1 | 59c77aed22cfd8395ddf3becff9feb7a187b4f17 -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/maven-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | uk.ac.shef.wit 4 | simmetrics 5 | 6 | 1.6.2 7 | 8 | 1.6.2 9 | 10 | 20140201152801 11 | 12 | 13 | -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/maven-metadata.xml.md5: -------------------------------------------------------------------------------- 1 | 46680cf725265adfa2b7513b54b3ea9c -------------------------------------------------------------------------------- /spring-batch-scalability/repo/uk/ac/shef/wit/simmetrics/maven-metadata.xml.sha1: -------------------------------------------------------------------------------- 1 | aa267239e66345cacd0d73dfbda42c2d5170015c -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/controller/RootController.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.controller; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Generator; 4 | import org.apache.commons.logging.Log; 5 | import org.apache.commons.logging.LogFactory; 6 | import org.springframework.batch.core.*; 7 | import org.springframework.batch.core.launch.JobLauncher; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | 15 | import java.io.File; 16 | import java.io.IOException; 17 | import java.util.concurrent.Callable; 18 | 19 | @Controller 20 | @RequestMapping("/") 21 | public final class RootController { 22 | 23 | private static final Log logger = LogFactory.getLog(RootController.class); 24 | 25 | @Autowired 26 | private Elixir0Generator elixir0Generator; 27 | 28 | @Autowired 29 | private JobLauncher jobLauncher; 30 | 31 | @Autowired 32 | private Job elixir0ImportJob; 33 | 34 | @RequestMapping(value = "/", method = RequestMethod.GET) 35 | public String goHome() { 36 | return "home"; 37 | } 38 | 39 | @RequestMapping(value = "/generate", method = RequestMethod.POST) 40 | public @ResponseBody Callable generateElixir0( 41 | @RequestParam("destinationFilePath") final String destinationFilePath, 42 | @RequestParam("numberOfTransactions") final int numberOfTransactions) throws IOException { 43 | 44 | return new Callable() { 45 | @Override 46 | public String call() throws Exception { 47 | logger.info(String.format("Generating Elixir0 message with %d transactions into %s", 48 | numberOfTransactions, destinationFilePath)); 49 | elixir0Generator.generate(new File(destinationFilePath), numberOfTransactions); 50 | return "Elixir0 message generated"; 51 | } 52 | }; 53 | } 54 | 55 | @RequestMapping(value = "/startJob", method = RequestMethod.POST) 56 | public @ResponseBody String startJob( 57 | @RequestParam("inputFilePath") final String inputFilePath, 58 | @RequestParam("scalingStrategy") final String scalingStrategy) throws JobExecutionException { 59 | 60 | logger.info(String.format("Starting import job for Elixir0 message %s", inputFilePath)); 61 | 62 | final JobParameters jobParameters = new JobParametersBuilder() 63 | .addString("inputFile", inputFilePath) 64 | .addString("scalingStrategy", scalingStrategy) 65 | .toJobParameters(); 66 | final JobExecution jobExecution = jobLauncher.run(elixir0ImportJob, jobParameters); 67 | return "Job started with ID=" + jobExecution.getJobId(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/processing/Elixir0Mapper.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | import com.ontheserverside.batch.bank.tx.TransactionStatus; 5 | import org.springframework.batch.item.file.mapping.FieldSetMapper; 6 | import org.springframework.batch.item.file.transform.FieldSet; 7 | import org.springframework.validation.BindException; 8 | 9 | public final class Elixir0Mapper implements FieldSetMapper { 10 | 11 | /** 12 | * Elixir0 message column names definition as used by {@link org.springframework.batch.item.file.transform.LineTokenizer}. 13 | */ 14 | public static final String COLUMN_NAMES = "paymentCode,paymentDate,amount,orderingPartySortCode,unused1,orderingPartyAccountNumber," 15 | + "beneficiaryAccountNumber,orderingPartyNameAndAddress,beneficiaryNameAndAddress,unused2,beneficiarySortCode," 16 | + "paymentDetails,unused3,unused4,transactionCode,clientBankInformation"; 17 | 18 | 19 | @Override 20 | public Elixir0Transaction mapFieldSet(final FieldSet fieldSet) throws BindException { 21 | 22 | final Elixir0Transaction tx = new Elixir0Transaction(); 23 | tx.setStatus(TransactionStatus.LOADED); 24 | 25 | tx.setPaymentCode(fieldSet.readInt("paymentCode")); 26 | tx.setPaymentDate(fieldSet.readDate("paymentDate", "yyyyMMdd")); 27 | tx.setAmount(fieldSet.readBigDecimal("amount")); 28 | tx.setOrderingPartySortCode(fieldSet.readString("orderingPartySortCode")); 29 | tx.setOrderingPartyAccountNumber(fieldSet.readString("orderingPartyAccountNumber")); 30 | tx.setBeneficiaryAccountNumber(fieldSet.readString("beneficiaryAccountNumber")); 31 | 32 | final String[] orderingPartyNameAndAddress = fieldSet.readString("orderingPartyNameAndAddress").split("\\|", 2); 33 | tx.setOrderingPartyName(orderingPartyNameAndAddress[0]); 34 | tx.setOrderingPartyAddress(orderingPartyNameAndAddress[1]); 35 | 36 | final String[] beneficiaryNameAndAddress = fieldSet.readString("beneficiaryNameAndAddress").split("\\|", 2); 37 | tx.setBeneficiaryName(beneficiaryNameAndAddress[0]); 38 | tx.setBeneficiaryAddress(beneficiaryNameAndAddress[1]); 39 | 40 | tx.setBeneficiarySortCode(fieldSet.readString("beneficiarySortCode")); 41 | tx.setPaymentDetails(fieldSet.readString("paymentDetails")); 42 | tx.setTransactionCode(fieldSet.readString("transactionCode")); 43 | tx.setClientBankInformation(fieldSet.readString("clientBankInformation")); 44 | 45 | return tx; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/processing/JobParameterExecutionDecider.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import org.springframework.batch.core.JobExecution; 4 | import org.springframework.batch.core.StepExecution; 5 | import org.springframework.batch.core.job.flow.FlowExecutionStatus; 6 | import org.springframework.batch.core.job.flow.JobExecutionDecider; 7 | import org.springframework.beans.factory.annotation.Required; 8 | 9 | public final class JobParameterExecutionDecider implements JobExecutionDecider { 10 | 11 | private String jobParameterKey; 12 | 13 | @Override 14 | public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { 15 | return new FlowExecutionStatus(jobExecution.getJobParameters().getString(jobParameterKey)); 16 | } 17 | 18 | @Required 19 | public void setJobParameterKey(String jobParameterKey) { 20 | this.jobParameterKey = jobParameterKey; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/processing/ModuloPartitioner.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import org.springframework.batch.core.partition.support.Partitioner; 4 | import org.springframework.batch.item.ExecutionContext; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public final class ModuloPartitioner implements Partitioner { 10 | 11 | public static final String MOD_DIVISOR_KEY = "mod.divisor"; 12 | public static final String MOD_REMAINDER_KEY = "mod.remainder"; 13 | 14 | @Override 15 | public Map partition(int gridSize) { 16 | final Map contextMap = new HashMap<>(); 17 | 18 | for (int i = 0; i < gridSize; i++) { 19 | ExecutionContext context = new ExecutionContext(); 20 | context.putInt(MOD_DIVISOR_KEY, gridSize); 21 | context.putInt(MOD_REMAINDER_KEY, i); 22 | contextMap.put(getPartitionName(i), context); 23 | } 24 | 25 | return contextMap; 26 | } 27 | 28 | private String getPartitionName(int index) { 29 | return String.format("partition-%d", index); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/processing/SynchronizedItemReaderDecorator.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import org.springframework.batch.item.*; 4 | 5 | public final class SynchronizedItemReaderDecorator implements ItemStream, ItemReader { 6 | 7 | private final ItemReader delegate; 8 | 9 | public SynchronizedItemReaderDecorator(ItemReader delegate) { 10 | this.delegate = delegate; 11 | } 12 | 13 | @Override 14 | public synchronized T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { 15 | return delegate.read(); 16 | } 17 | 18 | @Override 19 | public synchronized void open(ExecutionContext executionContext) throws ItemStreamException { 20 | if (delegate instanceof ItemStream) { 21 | ((ItemStream) delegate).open(executionContext); 22 | } 23 | } 24 | 25 | @Override 26 | public synchronized void update(ExecutionContext executionContext) throws ItemStreamException { 27 | if (delegate instanceof ItemStream) { 28 | ((ItemStream) delegate).update(executionContext); 29 | } 30 | } 31 | 32 | @Override 33 | public synchronized void close() throws ItemStreamException { 34 | if (delegate instanceof ItemStream) { 35 | ((ItemStream) delegate).close(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/FuzzyMatcher.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | /** 4 | * Strategy performing fuzzy matching of two sequences. Implementations may use 5 | * various distance metrics that best fit the particular purpose. 6 | */ 7 | public interface FuzzyMatcher { 8 | 9 | boolean sequencesMatching(String phrase1, String phrase2); 10 | } 11 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/JaroBagFuzzyMatcher.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import org.springframework.stereotype.Component; 4 | import uk.ac.shef.wit.simmetrics.similaritymetrics.InterfaceStringMetric; 5 | import uk.ac.shef.wit.simmetrics.similaritymetrics.Jaro; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | /** 12 | * {@link FuzzyMatcher} strategy implementation using Jaro metrics. 13 | * 14 | * @see FuzzyMatcher 15 | */ 16 | @Component 17 | public final class JaroBagFuzzyMatcher implements FuzzyMatcher { 18 | 19 | private static final double JARO_SINGLE_WORD_PHRASE_MIN_MATCH_FACTOR = 0.9; 20 | private static final double JARO_WORD_MIN_MATCH_FACTOR = 0.8333; 21 | private static final double BAG_MIN_MATCH_FACTOR = 0.932; 22 | 23 | private final InterfaceStringMetric jaroMetric = new Jaro(); 24 | 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | @Override 29 | public boolean sequencesMatching(final String phrase1, final String phrase2) { 30 | final String phrase1LowerCase = removeNonAlphanumeric(phrase1).toLowerCase(); 31 | final String phrase2LowerCase = removeNonAlphanumeric(phrase2).toLowerCase(); 32 | 33 | final List phrase1Bag = new ArrayList<>(Arrays.asList(phrase1LowerCase.split("\\s+"))); 34 | final List phrase2Bag = new ArrayList<>(Arrays.asList(phrase2LowerCase.split("\\s+"))); 35 | 36 | if (phrase1Bag.size() == 1 && phrase2Bag.size() == 1) { 37 | // single-word phrases deserve special treatment... 38 | return jaroMetric(phrase1LowerCase, phrase2LowerCase) >= JARO_SINGLE_WORD_PHRASE_MIN_MATCH_FACTOR; 39 | } else if (phrase1Bag.size() < phrase2Bag.size()) { 40 | return compareBags(phrase1Bag, phrase2Bag) >= BAG_MIN_MATCH_FACTOR; 41 | } else { 42 | return compareBags(phrase2Bag, phrase1Bag) >= BAG_MIN_MATCH_FACTOR; 43 | } 44 | } 45 | 46 | private double compareBags(final List bagA, final List bagB) { 47 | if (bagA.size() > bagB.size()) { 48 | throw new IllegalArgumentException("bagA size must be less than bagB size for algorithm to work!"); 49 | } 50 | 51 | double matchedLength = 0; 52 | double overalLength = 0; 53 | for (String word: bagA) { 54 | overalLength += word.length(); 55 | } 56 | for (String word: bagB) { 57 | overalLength += word.length(); 58 | } 59 | 60 | for (String a_word : bagA) { 61 | for (int i = 0; i < bagB.size(); i++) { 62 | String b_word = bagB.get(i); 63 | 64 | if (jaroMetric(a_word, b_word) > JARO_WORD_MIN_MATCH_FACTOR) { 65 | bagB.remove(i); 66 | matchedLength += a_word.length() + b_word.length(); 67 | break; 68 | } 69 | } 70 | } 71 | 72 | return matchedLength / overalLength; 73 | } 74 | 75 | private double jaroMetric(final String word1, final String word2) { 76 | return jaroMetric.getSimilarity(word1, word2); 77 | } 78 | 79 | private String removeNonAlphanumeric(final String str) { 80 | return str.replaceAll("[^a-zA-Z0-9\\s]", ""); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/SDNEntity.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.hibernate.annotations.Immutable; 5 | 6 | import javax.persistence.*; 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | @Entity 11 | @Immutable 12 | @Table(name = "SDN_ENTITY") 13 | public final class SDNEntity implements Serializable { 14 | 15 | @Id 16 | @Column(name = "UID") 17 | private long id; 18 | 19 | @Column(name = "NAME") 20 | private String name; 21 | 22 | @OneToMany(fetch = FetchType.EAGER) 23 | @JoinColumn(name = "ENTITY_UID") 24 | private List addresses; 25 | 26 | @ElementCollection(fetch = FetchType.EAGER) 27 | @CollectionTable( 28 | name = "SDN_ALTERNATE_NAME", 29 | joinColumns=@JoinColumn(name = "ENTITY_UID") 30 | ) 31 | @Column(name = "NAME") 32 | private List alternateNames; 33 | 34 | // hibernate requirement 35 | @Deprecated 36 | protected SDNEntity() { 37 | } 38 | 39 | public SDNEntity(String name, List addresses, List alternateNames) { 40 | this.name = name; 41 | this.addresses = addresses; 42 | this.alternateNames = alternateNames; 43 | } 44 | 45 | public String getName() { 46 | return this.name; 47 | } 48 | 49 | public List getAddresses() { 50 | return this.addresses; 51 | } 52 | 53 | public List getAlternateNames() { 54 | return this.alternateNames; 55 | } 56 | 57 | @Entity 58 | @Immutable 59 | @Table(name = "SDN_ADDRESS") 60 | public static class SDNAddress implements Serializable { 61 | 62 | @Id 63 | @Column(name = "ADDRESS_UID") 64 | private long id; 65 | 66 | @Column(name = "ADDRESS") 67 | private String address; 68 | 69 | @Column(name = "CITY") 70 | private String city; 71 | 72 | @Column(name = "COUNTRY") 73 | private String country; 74 | 75 | // hibernate requirement 76 | @Deprecated 77 | protected SDNAddress() { 78 | } 79 | 80 | public SDNAddress(String address, String city, String country) { 81 | this.address = address; 82 | this.city = city; 83 | this.country = country; 84 | } 85 | 86 | public String getFull() { 87 | return new StringBuilder() 88 | .append(StringUtils.defaultString(this.address)).append(" ") 89 | .append(StringUtils.defaultString(this.city)).append(" ") 90 | .append(StringUtils.defaultString(this.country)) 91 | .toString(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/SanctionMatch.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | 5 | import javax.persistence.*; 6 | 7 | @Entity 8 | @Table(name = "SANCTION_MATCH") 9 | public class SanctionMatch { 10 | 11 | @Id 12 | @GeneratedValue(strategy = GenerationType.AUTO) 13 | @Column(name = "ID") 14 | private long id; 15 | 16 | @OneToOne 17 | @JoinColumn(name = "TRANSACTION_ID") 18 | private Elixir0Transaction transaction; 19 | 20 | @OneToOne 21 | @JoinColumn(name = "SDN_ENTITY_ID") 22 | private SDNEntity sdnEntity; 23 | 24 | public SanctionMatch(Elixir0Transaction transaction, SDNEntity sdnEntity) { 25 | this.transaction = transaction; 26 | this.sdnEntity = sdnEntity; 27 | } 28 | 29 | public Elixir0Transaction getTransaction() { 30 | return transaction; 31 | } 32 | 33 | public SDNEntity getSdnEntity() { 34 | return sdnEntity; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/SanctionScreeningContext.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | 5 | import java.io.Serializable; 6 | 7 | public final class SanctionScreeningContext implements Serializable { 8 | 9 | private final Elixir0Transaction transaction; 10 | private final SDNEntity sdnEntity; 11 | 12 | public SanctionScreeningContext(Elixir0Transaction transaction, SDNEntity sdnEntity) { 13 | this.transaction = transaction; 14 | this.sdnEntity = sdnEntity; 15 | } 16 | 17 | public Elixir0Transaction getTransaction() { 18 | return this.transaction; 19 | } 20 | 21 | public SDNEntity getSdnEntity() { 22 | return this.sdnEntity; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/SanctionScreeningProcessor.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | import org.springframework.batch.item.ItemProcessor; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import static java.util.Arrays.asList; 10 | 11 | public final class SanctionScreeningProcessor implements ItemProcessor { 12 | 13 | @Autowired 14 | private FuzzyMatcher fuzzyMatcher; 15 | 16 | private final AbstractMatcher matcher = new CompositeMatcher(asList( 17 | new BeneficiaryNameMatcher(), 18 | new OrderingPartyNameMatcher(), 19 | new BeneficiaryAddressMatcher(), 20 | new OrderingPartyAddressMatcher(), 21 | new BeneficiaryAlternateNameMatcher(), 22 | new OrderingPartyAlternateNameMatcher() 23 | )); 24 | 25 | @Override 26 | public SanctionMatch process(SanctionScreeningContext context) { 27 | final Elixir0Transaction transaction = context.getTransaction(); 28 | final SDNEntity sdnEntity = context.getSdnEntity(); 29 | 30 | if (matcher.matches(transaction, sdnEntity)) { 31 | return new SanctionMatch(transaction, sdnEntity); 32 | } 33 | 34 | return null; 35 | } 36 | 37 | private final class BeneficiaryNameMatcher extends AbstractMatcher { 38 | @Override 39 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 40 | return fuzzyMatch(tx.getBeneficiaryName(), sdn.getName()); 41 | } 42 | } 43 | 44 | private final class OrderingPartyNameMatcher extends AbstractMatcher { 45 | @Override 46 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 47 | return fuzzyMatch(tx.getOrderingPartyName(), sdn.getName()); 48 | } 49 | } 50 | 51 | private final class BeneficiaryAddressMatcher extends AbstractMatcher { 52 | @Override 53 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 54 | final List fullAddresses = new LinkedList<>(); 55 | for (SDNEntity.SDNAddress address : sdn.getAddresses()) { 56 | fullAddresses.add(address.getFull()); 57 | } 58 | return fuzzyMatch(tx.getBeneficiaryAddress(), fullAddresses); 59 | } 60 | } 61 | 62 | private final class OrderingPartyAddressMatcher extends AbstractMatcher { 63 | @Override 64 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 65 | final List fullAddresses = new LinkedList<>(); 66 | for (SDNEntity.SDNAddress address : sdn.getAddresses()) { 67 | fullAddresses.add(address.getFull()); 68 | } 69 | return fuzzyMatch(tx.getOrderingPartyAddress(), fullAddresses); 70 | } 71 | } 72 | 73 | private final class BeneficiaryAlternateNameMatcher extends AbstractMatcher { 74 | @Override 75 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 76 | return fuzzyMatch(tx.getBeneficiaryName(), sdn.getAlternateNames()); 77 | } 78 | } 79 | 80 | private final class OrderingPartyAlternateNameMatcher extends AbstractMatcher { 81 | @Override 82 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 83 | return fuzzyMatch(tx.getOrderingPartyName(), sdn.getAlternateNames()); 84 | } 85 | } 86 | 87 | private final class CompositeMatcher extends AbstractMatcher { 88 | 89 | private final List matchers; 90 | 91 | public CompositeMatcher(List matchers) { 92 | this.matchers = matchers; 93 | } 94 | 95 | @Override 96 | public boolean matches(Elixir0Transaction tx, SDNEntity sdn) { 97 | for (AbstractMatcher matcher: matchers) { 98 | if (matcher.matches(tx, sdn)) { 99 | return true; 100 | } 101 | } 102 | 103 | return false; 104 | } 105 | } 106 | 107 | private abstract class AbstractMatcher { 108 | 109 | public abstract boolean matches(Elixir0Transaction tx, SDNEntity sdn); 110 | 111 | protected boolean fuzzyMatch(String str, String searchStr) { 112 | return fuzzyMatcher.sequencesMatching(str, searchStr); 113 | } 114 | 115 | protected boolean fuzzyMatch(String str, Iterable searchStrs) { 116 | for (String searchStr : searchStrs) { 117 | if (fuzzyMatch(str, searchStr)) { 118 | return true; 119 | } 120 | } 121 | 122 | return false; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/SanctionScreeningRecoveryCleaner.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.TransactionStatus; 4 | import org.hibernate.SessionFactory; 5 | import org.springframework.batch.core.StepExecution; 6 | import org.springframework.batch.core.listener.StepExecutionListenerSupport; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | /** 11 | * Cleans up stale date in case of re-entering sanction screening step during the job recovery. 12 | * Because of multithreaded nature of this step and unknown number of matches that are going to 13 | * be analysed for one transaction, this strategy fits better for this task than processing 14 | * status indicator column (can't really say if transaction has been completely screened or not). 15 | */ 16 | public final class SanctionScreeningRecoveryCleaner extends StepExecutionListenerSupport { 17 | 18 | @Autowired 19 | private SessionFactory sessionFactory; 20 | 21 | @Transactional 22 | @Override 23 | public void beforeStep(StepExecution stepExecution) { 24 | 25 | sessionFactory.getCurrentSession() 26 | .createQuery("delete from SanctionMatch where transaction.id in (" + 27 | "select tx.id from Elixir0Transaction as tx where tx.status = :status)") 28 | .setParameter("status", TransactionStatus.LOADED) 29 | .executeUpdate(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/screening/UpdateScreenedTransactionStatusTasklet.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.TransactionStatus; 4 | import org.hibernate.SessionFactory; 5 | import org.springframework.batch.core.StepContribution; 6 | import org.springframework.batch.core.scope.context.ChunkContext; 7 | import org.springframework.batch.core.step.tasklet.Tasklet; 8 | import org.springframework.batch.repeat.RepeatStatus; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | 11 | public final class UpdateScreenedTransactionStatusTasklet implements Tasklet { 12 | 13 | @Autowired 14 | private SessionFactory sessionFactory; 15 | 16 | @Override 17 | public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { 18 | 19 | sessionFactory.getCurrentSession() 20 | .createQuery("update Elixir0Transaction as tx set tx.status = :status where tx in (" + 21 | "select sm.transaction from SanctionMatch as sm)") 22 | .setParameter("status", TransactionStatus.SUSPENDED) 23 | .executeUpdate(); 24 | 25 | sessionFactory.getCurrentSession() 26 | .createQuery("update Elixir0Transaction as tx set tx.status = :status where tx not in (" + 27 | "select sm.transaction from SanctionMatch as sm)") 28 | .setParameter("status", TransactionStatus.ACCEPTED) 29 | .executeUpdate(); 30 | 31 | return RepeatStatus.FINISHED; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/tx/Elixir0Generator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ontheserverside.batch.bank.tx; 18 | 19 | import java.io.File; 20 | import java.io.IOException; 21 | 22 | /** 23 | * Generates Elixir0 file containing random transactions. 24 | */ 25 | public interface Elixir0Generator { 26 | 27 | void generate(File outputFile, int numberOfTransactions) throws IOException; 28 | } 29 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/tx/Elixir0Transaction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ontheserverside.batch.bank.tx; 18 | 19 | import org.apache.commons.lang3.ArrayUtils; 20 | import org.apache.commons.lang3.builder.ToStringBuilder; 21 | import org.apache.commons.lang3.builder.ToStringStyle; 22 | 23 | import javax.persistence.*; 24 | import java.io.Serializable; 25 | import java.math.BigDecimal; 26 | import java.text.SimpleDateFormat; 27 | import java.util.Date; 28 | 29 | /** 30 | * Represents Elixir0 domestic transaction loaded from file. 31 | * 32 | * Elixir0 is a country-domestic format used by Polish banking systems. 33 | * It may contain standard credit transfer transactions as well as social 34 | * security and tax payments. 35 | */ 36 | @Entity 37 | @Table(name = "ELIXIR0_TX") 38 | public final class Elixir0Transaction implements Serializable { 39 | 40 | public static final int PAYMENT_CODE_LOCAL = 110; 41 | 42 | public static final String TRANSACTION_CODE_CT = "51"; 43 | 44 | /** 45 | * Names of fields declared as a 'text type' fields by the elixir0 format 46 | */ 47 | private static final String[] TEXT_FIELDS = { 48 | "orderingPartyAccountNumber", 49 | "beneficiaryAccountNumber", 50 | "orderingPartyNameAndAddress", 51 | "beneficiaryNameAndAddress", 52 | "paymentDetails", 53 | "transactionCode", 54 | "clientBankInformation" 55 | }; 56 | 57 | private static final ToStringStyle TO_STRING_STYLE = new TxToStringStyle(); 58 | 59 | @Id 60 | @GeneratedValue(strategy = GenerationType.AUTO) 61 | @Column(name = "ID") 62 | private long id; 63 | 64 | @Enumerated(EnumType.STRING) 65 | @Column(name = "STATUS") 66 | private TransactionStatus status; 67 | 68 | @Column(name = "PAYMENT_CODE") 69 | private int paymentCode; 70 | 71 | @Column(name = "PAYMENT_DATE") 72 | private Date paymentDate; 73 | 74 | @Column(name = "AMOUNT") 75 | private BigDecimal amount; 76 | 77 | @Column(name = "ORDERING_PARTY_SORT_CODE") 78 | private String orderingPartySortCode; 79 | 80 | @Column(name = "ORDERING_PARTY_ACCOUNT_NUMBER") 81 | private String orderingPartyAccountNumber; 82 | 83 | @Column(name = "BENEFICIARY_ACCOUNT_NUMBER") 84 | private String beneficiaryAccountNumber; 85 | 86 | @Column(name = "ORDERING_PARTY_NAME") 87 | private String orderingPartyName; 88 | 89 | @Column(name = "ORDERING_PARTY_ADDRESS") 90 | private String orderingPartyAddress; 91 | 92 | @Column(name = "BENEFICIARY_NAME") 93 | private String beneficiaryName; 94 | 95 | @Column(name = "BENEFICIARY_ADDRESS") 96 | private String beneficiaryAddress; 97 | 98 | @Column(name = "BENEFICIARY_SORT_CODE") 99 | private String beneficiarySortCode; 100 | 101 | @Column(name = "PAYMENT_DETAILS") 102 | private String paymentDetails; 103 | 104 | // fields below are used only for social security and tax payments 105 | // their values should be extracted from 'paymentDetails' section 106 | @Column(name = "PAYERS_NIP") 107 | private String payersNip; 108 | @Column(name = "IDENTIFIER_TYPE") 109 | private String identifierType; 110 | @Column(name = "PAYERS_IDENTIFICATION") 111 | private String payersIdentification; 112 | @Column(name = "PAYMENT_TYPE") 113 | private String paymentType; 114 | @Column(name = "PAYMENT_PERIOD") 115 | private Date paymentPeriod; 116 | @Column(name = "PERIOD_FORM_NUMBER") 117 | private String periodFormNumber; 118 | @Column(name = "ADDITIONAL_CASE_ID") 119 | private String additionalCaseID; 120 | 121 | @Column(name = "TRANSACTION_CODE") 122 | private String transactionCode; 123 | 124 | @Column(name = "CLIENT_BANK_INFORMATION") 125 | private String clientBankInformation; 126 | 127 | 128 | public TransactionStatus getStatus() { 129 | return status; 130 | } 131 | 132 | public void setStatus(TransactionStatus status) { 133 | this.status = status; 134 | } 135 | 136 | public int getPaymentCode() { 137 | return paymentCode; 138 | } 139 | 140 | public void setPaymentCode(int paymentCode) { 141 | this.paymentCode = paymentCode; 142 | } 143 | 144 | public Date getPaymentDate() { 145 | return paymentDate; 146 | } 147 | 148 | public void setPaymentDate(Date paymentDate) { 149 | this.paymentDate = paymentDate; 150 | } 151 | 152 | public BigDecimal getAmount() { 153 | return amount; 154 | } 155 | 156 | public void setAmount(BigDecimal amount) { 157 | this.amount = amount; 158 | } 159 | 160 | public String getOrderingPartySortCode() { 161 | return orderingPartySortCode; 162 | } 163 | 164 | public void setOrderingPartySortCode(String orderingPartySortCode) { 165 | this.orderingPartySortCode = orderingPartySortCode; 166 | } 167 | 168 | public String getOrderingPartyAccountNumber() { 169 | return orderingPartyAccountNumber; 170 | } 171 | 172 | public void setOrderingPartyAccountNumber(String orderingPartyAccountNumber) { 173 | this.orderingPartyAccountNumber = orderingPartyAccountNumber; 174 | } 175 | 176 | public String getBeneficiaryAccountNumber() { 177 | return beneficiaryAccountNumber; 178 | } 179 | 180 | public void setBeneficiaryAccountNumber(String beneficiaryAccountNumber) { 181 | this.beneficiaryAccountNumber = beneficiaryAccountNumber; 182 | } 183 | 184 | public String getOrderingPartyName() { 185 | return orderingPartyName; 186 | } 187 | 188 | public void setOrderingPartyName(String orderingPartyName) { 189 | this.orderingPartyName = orderingPartyName; 190 | } 191 | 192 | public String getOrderingPartyAddress() { 193 | return orderingPartyAddress; 194 | } 195 | 196 | public void setOrderingPartyAddress(String orderingPartyAddress) { 197 | this.orderingPartyAddress = orderingPartyAddress; 198 | } 199 | 200 | public String getBeneficiaryName() { 201 | return beneficiaryName; 202 | } 203 | 204 | public void setBeneficiaryName(String beneficiaryName) { 205 | this.beneficiaryName = beneficiaryName; 206 | } 207 | 208 | public String getBeneficiaryAddress() { 209 | return beneficiaryAddress; 210 | } 211 | 212 | public void setBeneficiaryAddress(String beneficiaryAddress) { 213 | this.beneficiaryAddress = beneficiaryAddress; 214 | } 215 | 216 | public String getBeneficiarySortCode() { 217 | return beneficiarySortCode; 218 | } 219 | 220 | public void setBeneficiarySortCode(String beneficiarySortCode) { 221 | this.beneficiarySortCode = beneficiarySortCode; 222 | } 223 | 224 | public String getPaymentDetails() { 225 | return paymentDetails; 226 | } 227 | 228 | public void setPaymentDetails(String paymentDetails) { 229 | this.paymentDetails = paymentDetails; 230 | } 231 | 232 | public String getPayersNip() { 233 | return payersNip; 234 | } 235 | 236 | public void setPayersNip(String payersNip) { 237 | this.payersNip = payersNip; 238 | } 239 | 240 | public String getIdentifierType() { 241 | return identifierType; 242 | } 243 | 244 | public void setIdentifierType(String identifierType) { 245 | this.identifierType = identifierType; 246 | } 247 | 248 | public String getPayersIdentification() { 249 | return payersIdentification; 250 | } 251 | 252 | public void setPayersIdentification(String payersIdentification) { 253 | this.payersIdentification = payersIdentification; 254 | } 255 | 256 | public String getPaymentType() { 257 | return paymentType; 258 | } 259 | 260 | public void setPaymentType(String paymentType) { 261 | this.paymentType = paymentType; 262 | } 263 | 264 | public Date getPaymentPeriod() { 265 | return paymentPeriod; 266 | } 267 | 268 | public void setPaymentPeriod(Date paymentPeriod) { 269 | this.paymentPeriod = paymentPeriod; 270 | } 271 | 272 | public String getPeriodFormNumber() { 273 | return periodFormNumber; 274 | } 275 | 276 | public void setPeriodFormNumber(String periodFormNumber) { 277 | this.periodFormNumber = periodFormNumber; 278 | } 279 | 280 | public String getAdditionalCaseID() { 281 | return additionalCaseID; 282 | } 283 | 284 | public void setAdditionalCaseID(String additionalCaseID) { 285 | this.additionalCaseID = additionalCaseID; 286 | } 287 | 288 | public String getTransactionCode() { 289 | return transactionCode; 290 | } 291 | 292 | public void setTransactionCode(String transactionCode) { 293 | this.transactionCode = transactionCode; 294 | } 295 | 296 | public String getClientBankInformation() { 297 | return clientBankInformation; 298 | } 299 | 300 | public void setClientBankInformation(String clientBankInformation) { 301 | this.clientBankInformation = clientBankInformation; 302 | } 303 | 304 | @Override 305 | public String toString() { 306 | return new ToStringBuilder(this, TO_STRING_STYLE) 307 | .append("paymentCode", paymentCode) 308 | .append("paymentDate", paymentDate) 309 | .append("amount", amount) 310 | .append("orderingPartySortCode", orderingPartySortCode) 311 | .append("0") // hardcoded as '0' in the format definition 312 | .append("orderingPartyAccountNumber", orderingPartyAccountNumber) 313 | .append("beneficiaryAccountNumber", beneficiaryAccountNumber) 314 | .append("orderingPartyNameAndAddress", String.format("%s|%s", 315 | orderingPartyName != null ? orderingPartyName : "", 316 | orderingPartyAddress != null ? orderingPartyAddress : "")) 317 | .append("beneficiaryNameAndAddress", String.format("%s|%s", 318 | beneficiaryName != null ? beneficiaryName : "", 319 | beneficiaryAddress != null ? beneficiaryAddress : "")) 320 | .append("0") // hardcoded as '0' in the format definition 321 | .append("beneficiarySortCode", beneficiarySortCode) 322 | .append("paymentDetails", paymentDetails) 323 | .append("") // hardcoded as empty in the format definition 324 | .append("") // hardcoded as empty in the format definition 325 | .append("transactionCode", transactionCode) 326 | .append("clientBankInformation", clientBankInformation) 327 | .toString(); 328 | } 329 | 330 | private static class TxToStringStyle extends ToStringStyle { 331 | 332 | TxToStringStyle() { 333 | super(); 334 | this.setUseClassName(false); 335 | this.setUseIdentityHashCode(false); 336 | this.setUseFieldNames(false); 337 | this.setContentStart(""); 338 | this.setContentEnd(""); 339 | this.setNullText(""); 340 | } 341 | 342 | @Override 343 | protected void appendFieldStart(StringBuffer buffer, String fieldName) { 344 | super.appendFieldStart(buffer, fieldName); 345 | 346 | if (ArrayUtils.contains(TEXT_FIELDS, fieldName)) { 347 | buffer.append("\""); 348 | } 349 | } 350 | 351 | @Override 352 | protected void appendFieldEnd(StringBuffer buffer, String fieldName) { 353 | if (ArrayUtils.contains(TEXT_FIELDS, fieldName)) { 354 | buffer.append("\""); 355 | } 356 | 357 | super.appendFieldEnd(buffer, fieldName); 358 | } 359 | 360 | @Override 361 | protected void appendDetail(StringBuffer buffer, String fieldName, Object value) { 362 | if (value instanceof Date) { 363 | value = new SimpleDateFormat("yyyyMMdd").format(value); 364 | } 365 | 366 | buffer.append(value); 367 | } 368 | } 369 | } -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/java/com/ontheserverside/batch/bank/tx/SimpleElixir0Generator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ontheserverside.batch.bank.tx; 18 | 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.core.io.Resource; 21 | import org.springframework.stereotype.Component; 22 | 23 | import javax.annotation.PostConstruct; 24 | import java.io.*; 25 | import java.math.BigDecimal; 26 | import java.math.BigInteger; 27 | 28 | import java.nio.charset.StandardCharsets; 29 | import java.nio.file.Files; 30 | import java.util.*; 31 | 32 | @Component 33 | public final class SimpleElixir0Generator implements Elixir0Generator { 34 | 35 | @javax.annotation.Resource 36 | @Value("classpath:names.txt") 37 | private Resource paymentPartyNamesResource; 38 | 39 | @javax.annotation.Resource 40 | @Value("classpath:addresses.txt") 41 | private Resource paymentPartyAddressesResource; 42 | 43 | @javax.annotation.Resource 44 | @Value("classpath:dictionary.txt") 45 | private Resource dictionaryResource; 46 | 47 | private final List paymentPartyNames = new LinkedList<>(); 48 | private final List paymentPartyAddresses = new LinkedList<>(); 49 | private final List words = new LinkedList<>(); 50 | 51 | @PostConstruct 52 | private void loadExternalDataResources() throws IOException { 53 | paymentPartyNames.addAll(loadLinesFromFile(paymentPartyNamesResource)); 54 | paymentPartyAddresses.addAll(loadLinesFromFile(paymentPartyAddressesResource)); 55 | words.addAll(loadLinesFromFile(dictionaryResource)); 56 | } 57 | 58 | // note: usage of this method is reasonable only for relatively small files! 59 | private List loadLinesFromFile(final Resource resource) throws IOException { 60 | return Files.readAllLines(resource.getFile().toPath(), 61 | StandardCharsets.UTF_8); 62 | } 63 | 64 | @Override 65 | public void generate(final File outputFile, final int numberOfTransactions) throws IOException { 66 | final TxGenerator txGenerator = new TxGenerator(); 67 | final BufferedWriter writer = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8); 68 | try { 69 | for (int i=0; i 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/META-INF/spring/batchContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/META-INF/spring/elixir0ImportJob.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | SELECT NEW com.ontheserverside.batch.bank.screening.SanctionScreeningContext (tx, entity) 109 | FROM Elixir0Transaction tx, SDNEntity entity 110 | WHERE tx.status = :txStatus 111 | ORDER BY tx.id 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | SELECT NEW com.ontheserverside.batch.bank.screening.SanctionScreeningContext (tx, entity) 130 | FROM Elixir0Transaction tx, SDNEntity entity 131 | WHERE tx.status = :txStatus 132 | ORDER BY tx.id 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | SELECT NEW com.ontheserverside.batch.bank.screening.SanctionScreeningContext (tx, entity) 149 | FROM Elixir0Transaction tx, SDNEntity entity 150 | WHERE tx.status = :txStatus 151 | AND mod(tx.id, :modDivisor) = :modRemainder 152 | ORDER BY tx.id 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | inputFile 182 | scalingStrategy 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/META-INF/spring/hibernateContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | com.ontheserverside.batch.bank 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.hibernate.dialect.H2Dialect 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/META-INF/spring/jmsContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | java.naming.factory.initial=net.timewalker.ffmq3.jndi.FFMQInitialContextFactory 21 | java.naming.provider.url=tcp://localhost:10002 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 38 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | 68 | 69 | 71 | 72 | 73 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/addresses.txt: -------------------------------------------------------------------------------- 1 | 2067 Gentle Sky Orchard, Mousetail, Alabama, 35330-7376, US 2 | 4074 Heather Corner, Luck, Alabama, 35398-0918, US 3 | 4791 Golden Acres, Beans Corner, Ontario, L4A-8V5, CA 4 | 7375 Quiet Zephyr Avenue, Humble City, South Dakota, 57605-5698, US 5 | 7780 Hazy Autumn Line, Swastika, Oklahoma, 73436-8342, US 6 | 5191 Shady Wagon Common, Joshua Tree, Mississippi, 38801-7578, US 7 | 1470 Easy Ridge, Keen-Wik, Texas, 78009-8992, US 8 | 4182 Misty Embers Vista, Martensville, Nunavut, X0F-5J2, CA 9 | 4492 Tawny Village, Buddha, New Jersey, 08383-1228, US 10 | 8978 Merry Trace, Shaft Ox Corner, Vermont, 05618-6954, US 11 | 9144 Grand Gate Glade, Red Scaffold, Wyoming, 82305-1040, US 12 | 1444 Rustic Corners, Oddville, Wyoming, 83029-7376, US 13 | 9173 Quaking Panda Quay, Sand Draw, Missouri, 64091-6390, US 14 | 75 Round Rise Grounds, Jumpertown, Arkansas, 71941-9808, US 15 | 7058 Jagged Green, Purchase, Michigan, 48597-2405, US 16 | 5310 Fallen Rise, Kinistino, Arizona, 86334-1987, US 17 | 1709 Emerald Stead, Swisher, Yukon, Y0E-9S9, CA 18 | 2048 Umber Berry Townline, Doolittle, New Mexico, 88038-7543, US 19 | 3093 Green Forest Place, Benefit, Vermont, 05331-1955, US 20 | 8128 Rocky Pine Front, Nokomis, Alberta, T0K-1O3, CA 21 | 8905 Foggy Promenade, Musk Ox, Nebraska, 69995-8936, US 22 | 3943 Pleasant Plaza, Uncle Sam, Arizona, 85565-6408, US 23 | 8231 Sleepy Abbey, Shakespeare, New Mexico, 88069-6553, US 24 | 8200 Honey Impasse, Sigourney, Hawaii, 96875-4553, US 25 | 1501 Clear By-pass, Tilsonburg, Northwest Territories, X6X-7Q5, CA 26 | 8876 Harvest Leaf Harbour, Fighting Rock Corner, Maryland, 21069-9972, US 27 | 6822 Amber Landing, The Black Cat, Kansas, 67889-2191, US 28 | 3019 Blue Mount, Swindleville, Ohio, 43262-8184, US 29 | 127 Red Hills Cove, Weyauwega, Kansas, 66955-7256, US 30 | 1617 Little Concession, Muitzeskill, Indiana, 46129-4378, US 31 | 3997 Lost Square, Syndicate, Florida, 33682-2268, US 32 | 6310 Broad Alley, Seventysix, Ohio, 43624-2085, US 33 | 6309 Old Park, Loves Corner, Vermont, 05780-7002, US 34 | 2205 Cozy Prairie Turnabout, Miami Beach, Hawaii, 96813-3312, US 35 | 7782 Lazy Path, Tangipahoa, Massachusetts, 02010-6477, US 36 | 275 High Horse Carrefour, Speedway, South Dakota, 57963-6449, US 37 | 3653 Burning Shadow Island, Hustle, Maine, 04509-1256, US 38 | 7062 Cinder Spring Trail, Waldron, Hawaii, 96849-0191, US 39 | 2344 Cotton Grove Mountain, Blue Anchor, Utah, 84383-1180, US 40 | 4608 Velvet Elk Boulevard, Gnaw Bone, District of Columbia, 20038-6201, US 41 | 2441 Noble Bluff Close, Coldfoot, Illinois, 62518-4030, US 42 | 4489 Sunny Hickory Terrace, Enderby, Iowa, 50157-9431, US 43 | 3805 Wishing Centre, Presidential, New York, 12655-9090, US 44 | 5257 Silent Range, Eighty Four, Oregon, 97408-9448, US 45 | 603 Iron Fox Farm, Bacons Quarters, Prince Edward Island, C3X-7R3, CA 46 | 1116 Middle Pines, Jinks, Saskatchewan, S7R-1U8, CA 47 | 3799 Thunder Treasure Wynd, Chickville, Arkansas, 71917-4851, US 48 | 306 Hidden Campus, Chevy Chase, Montana, 59521-3813, US 49 | 5784 Crystal Villas, Freeze, Michigan, 49662-9562, US 50 | 9510 Silver Wood, Lick Skillet, Iowa, 51093-5843, US -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=INFO, stdout 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/resources/names.txt: -------------------------------------------------------------------------------- 1 | ABIDJAN FREIGHT 2 | AIR CESS 3 | AIR ZORY LTD. 4 | AIRBAS TRANSPORTATION FZE 5 | AL FIDA INTERNATIONAL GENERAL TRADING 6 | AL HILAL EXCHANGE 7 | AL MASHREQ INVESTMENT FUND 8 | ALLAN GRANGE FARM 9 | AMIN INVESTMENT BANK 10 | ATC LTD. 11 | AUCHENBURG FARM 12 | Abby Allbright 13 | Abd al-Rahman Al-Faqih 14 | Abdulbaqi Mohammed Khaled 15 | Abraham Pedroso 16 | Abu Bakr Yunis Jabir 17 | Abu Zaid Dorda 18 | Adan Grief 19 | Adelina Capobianco 20 | Adelina Royston 21 | Adena Ammon 22 | Adena Giraud 23 | Adena Tye 24 | Adrian Petri 25 | Adriane Schade 26 | Adrianna Falcone 27 | Adrianne Ballas 28 | Adriene Solorio 29 | Afton Hatter 30 | Aide Carrozza 31 | Aileen Zerangue 32 | Al Aburto 33 | Alan Dipiazza 34 | Alan Gabriel 35 | Alane Sondag 36 | Alberta Thackston 37 | Albertha Etheredge 38 | Albertina Michaux 39 | Alda Bullen 40 | Alejandra Corner 41 | Aleta Verdin 42 | Alfred Franceschini 43 | Ali Orellana 44 | Alicia Rusnak 45 | Alina Negron 46 | Alix Killion 47 | Alix Sprouse 48 | Allan Dymond 49 | Allegra Victorian 50 | Allena Earnest 51 | Alline Lamy 52 | Allyson Fleener 53 | Alma Hoehne 54 | Alma Kamm 55 | Almeta Cropper 56 | Alona Braga 57 | Alpha Horsman 58 | Alvina Wingerter 59 | Alysha Rosenow 60 | Alyssa Cermak 61 | Ambrose Braud 62 | Amina Brunson 63 | Amira Campoverde 64 | Amparo Harrah 65 | Anabel Babcock 66 | Anabel Ogles 67 | Anabel Reta 68 | Analisa Borge 69 | Anastacia Trepanier 70 | Andrea Spano 71 | Andria Morell 72 | Andria Zelman 73 | Andy Pulsifer 74 | Andy Yates 75 | Angelo Konecny 76 | Angie Elrod 77 | Anisa Bring 78 | Anja Hallum 79 | Ann Rogers 80 | Annalee Dees 81 | Annalisa Villavicencio 82 | Annamarie Hanline 83 | Anneliese Waterbury 84 | Annemarie Raphael 85 | Annita Silver 86 | Anthony Ung 87 | Antione Fortenberry 88 | Antoinette Gregory 89 | Antonina Auger 90 | Antonio Ford 91 | April Elsen 92 | Aracely Southward 93 | Arcelia White 94 | Ardella Blackston 95 | Ardelle Sabbagh 96 | Arianne Oathout 97 | Arica Boehmer 98 | Arlean Kantor 99 | Arleen Klassen 100 | Arlena Lavallee 101 | Arlene Warn 102 | Arlie Nylander 103 | Arlie Schaller 104 | Armanda Stalls 105 | Armida Kohout 106 | Artie Stanford 107 | Arvilla Marquess 108 | Asha Kaiser 109 | Ashanti Haigler 110 | Ashlea Nachman 111 | Ashli Rhynes 112 | Asia Lemanski 113 | Asia Mikesell 114 | Athena Nimmons 115 | Audie Michalik 116 | Audrea Eisen 117 | Audria Gassett 118 | Aura Maus 119 | Aurore Buckland 120 | Avery Fall 121 | Azzie Packett 122 | BAMBOO CREEK FARM 123 | BEHSAZ KASHANE TEHRAN CONSTRUCTION CO. 124 | BENA PROPERTIES 125 | BOURNE FARM 126 | BUKAVU AVIATION TRANSPORT 127 | BUSINESS AIR SERVICES 128 | Babette Heyd 129 | Bao Tomblin 130 | Barb Tribble 131 | Bari Dorris 132 | Bart Edberg 133 | Barton Cossette 134 | Barton Simo 135 | Beatrice Loeb 136 | Beatris Duane 137 | Becky Garrard 138 | Belkis Poff 139 | Benita Oquendo 140 | Benjamin Severe 141 | Benny Voisin 142 | Bernadine Hakala 143 | Bernadine Kentner 144 | Bernardina Lockard 145 | Bernardine Huson 146 | Berta Claeys 147 | Beryl Rothwell 148 | Bessie Ortiz 149 | Beth Hammond 150 | Bethany Reid 151 | Betty Hundt 152 | Beverly Bumgardner 153 | Billy Chumley 154 | Billye Bolanos 155 | Billye Cullinan 156 | Blair Rhynes 157 | Blanca Rojero 158 | Blanche Worthey 159 | Blossom Gau 160 | Blossom Vandervoort 161 | Bobbie Hackler 162 | Bobby Branch 163 | Bok Kitamura 164 | Bonita Donelan 165 | Boyce Aston 166 | Boyce Brannigan 167 | Boyce Herrada 168 | Boyce Mcintyre 169 | Boyd Holmes 170 | Brad Mcfaddin 171 | Branda Headley 172 | Brande Favero 173 | Brandie Elridge 174 | Brandon Beer 175 | Brandon Crary 176 | Breanne Shira 177 | Bree Macedo 178 | Brenda Berens 179 | Brigida Svendsen 180 | Britney Vierling 181 | Brittaney Caplinger 182 | Brittaney Witcher 183 | Brook Faries 184 | Bruce Cook 185 | Brunilda Pardon 186 | Buddy Pomerleau 187 | Buford Gehling 188 | CENTRAFRICAN AIRLINES 189 | CENTRAL AFRICA DEVELOPMENT FUND 190 | CET AVIATION ENTERPRISE, FZE 191 | CHAM HOLDING 192 | CHICHAKLI & ASSOCIATES PLLC 193 | COLD COMFORT FARM TRUST CO-OPERATIVE 194 | CONTINUE PROFESSIONAL EDUCATION INC. 195 | CORBURN 13 FARM 196 | CYLINDER SYSTEM L.T.D. 197 | Caitlin Kiker 198 | Calista Ko 199 | Cami Rico 200 | Camila Mixon 201 | Candra Wilkie 202 | Candyce Woerner 203 | Carey Eveland 204 | Carleen Scaglione 205 | Carlena Level 206 | Carley Teed 207 | Carmen Bones 208 | Carol Capito 209 | Carri Hitch 210 | Carrie Hinson 211 | Carrie Weber 212 | Carroll Stansell 213 | Carter Bellantoni 214 | Carter Kelly 215 | Carylon Canaday 216 | Casandra Vause 217 | Casimira Urquhart 218 | Catharine Wingard 219 | Catherin Krebs 220 | Catheryn Josephs 221 | Cathryn Mateo 222 | Catrina Richert 223 | Catrina Swanigan 224 | Cecelia Wood 225 | Cedrick Fabrizio 226 | Celestina Favor 227 | Celsa Schirmer 228 | Ceola Simms 229 | Chan Simpler 230 | Chandra Grewell 231 | Chanell Aguillard 232 | Chanelle Trollinger 233 | Chang Umana 234 | Chante Gatti 235 | Charita Beckford 236 | Charlette Stutz 237 | Charlie Armstrong 238 | Charlotte Woodring 239 | Charmaine Ekhoff 240 | Chase Fiscus 241 | Chelsey Bjornson 242 | Chelsey Bushman 243 | Cher Hypolite 244 | Chere Friberg 245 | Cheryll Deems 246 | Cheyenne Abeita 247 | Chia Bumpus 248 | Chin Marrinan 249 | China Shumway 250 | Chong Zimmer 251 | Christian Board 252 | Christinia Ickes 253 | Christoper Khalil 254 | Christopher Gourdine 255 | Christy Flowers 256 | Chun Hiller 257 | Ciara Averitt 258 | Clair Holaway 259 | Claretha Lastrapes 260 | Claretta Grillo 261 | Clarisa Widrick 262 | Clarissa Acuff 263 | Classie Hartin 264 | Clemente Fulp 265 | Cleta Chaney 266 | Clifford Berry 267 | Clint Tokar 268 | Cody Acres 269 | Colby Hitt 270 | Colby Klein 271 | Coletta Harshaw 272 | Colleen Palmer 273 | Collin Murnane 274 | Consuela Gisi 275 | Contessa Tisby 276 | Cora Fidler 277 | Coralee Vargas 278 | Cordia Oubre 279 | Coreen Ruble 280 | Corine Charette 281 | Corinna Tejera 282 | Corliss Ducker 283 | Cornelius Sobotka 284 | Corrine Fulcher 285 | Cortez Haggard 286 | Craig Robbins 287 | Cris Mayo 288 | Criselda Claggett 289 | Cristen Suddeth 290 | Cristi Michalec 291 | Crystle Schuh 292 | Cuc Levalley 293 | Curt Montiel 294 | Cyrstal Heasley 295 | DAYTONA POOLS, INC. 296 | DBARDI, S.A. DE C.V. 297 | DHH ENTERPRISES, INC. 298 | Daisey Symonds 299 | Dale Bright 300 | Dalia Greenberg 301 | Dalila Nakamura 302 | Dallas Klatt 303 | Damian Soller 304 | Dana Kisling 305 | Danica Mcdonalds 306 | Daniele Hagen 307 | Danika Hixon 308 | Danna Ciesielski 309 | Danny Harpe 310 | Dante Budzinski 311 | Dante Tankersley 312 | Danuta Hennessey 313 | Dara Seng 314 | Darcel Seymore 315 | Darci Telfer 316 | Darin Peters 317 | Darin Villanveva 318 | Darlena Ying 319 | Daron Tavarez 320 | Darrick Archer 321 | Darron Swindell 322 | Darryl Joseph 323 | Darwin Eure 324 | Davina Lukas 325 | Dayle Kyzer 326 | Deana Gaona 327 | Deann Wormley 328 | Debbra Lamorte 329 | Debera Auten 330 | Deeann Speaker 331 | Deeanna Vannatter 332 | Delena Mcgreevy 333 | Delfina Roses 334 | Delinda Wedel 335 | Della Aston 336 | Delmar Larocco 337 | Delora Courser 338 | Delpha Loughman 339 | Delta Crumbley 340 | Delta Griffie 341 | Demetra Blumstein 342 | Demetra Sutphin 343 | Denice Quan 344 | Denna Lones 345 | Dennise Arce 346 | Denver Bonier 347 | Deshawn Guardiola 348 | Desirae Twitchell 349 | Desmond Gravely 350 | Dewey Fox 351 | Diana Hutchens 352 | Dianna Linsley 353 | Dick Highfield 354 | Diego Newnam 355 | Dieman Abdulkadir Izzat 356 | Digna Radke 357 | Dione Shumpert 358 | Dionne Mair 359 | Dolores Novick 360 | Domenica Addison 361 | Domenica Bensley 362 | Dominica Pelfrey 363 | Domitila Latch 364 | Dong Deady 365 | Dong Petree 366 | Donnie Walko 367 | Donya Ingle 368 | Doreen Myers 369 | Dorethea Plumadore 370 | Dorian Blackledge 371 | Doris Freed 372 | Doris Santos 373 | Doug Mckenney 374 | Douglas Heald 375 | Douglass Voight 376 | Doyle White 377 | Drucilla Keese 378 | Duane Sparks 379 | Dylan Kanne 380 | EIRIN FARM 381 | EXECUTION OF IMAM KHOMEINI'S ORDER 382 | EYRIE FARM 383 | Earlene Severson 384 | Earlie Barcus 385 | Earline Stotz 386 | Earnest Doxey 387 | Earnest French 388 | Eboni Hetherington 389 | Eda Bucklin 390 | Edelmira Dacosta 391 | Edelmira Wever 392 | Eden Bump 393 | Edgar Mcphee 394 | Edie Barrington 395 | Edith Saunders 396 | Edmond Hoelscher 397 | Edmundo Mcbroom 398 | Edmundo Rutledge 399 | Eduardo Terry 400 | Edwardo Ehrhardt 401 | Edwin Hassett 402 | Edwin Roehl 403 | Edyth Reitzel 404 | Ehtel Poole 405 | Elana Packard 406 | Elayne Wykoff 407 | Elden Cooley 408 | Eldridge Capella 409 | Elena Jiggetts 410 | Elenora Havlik 411 | Eleonora Jan 412 | Eleonora Salas 413 | Elia Desrosier 414 | Eliana Maddock 415 | Elias Raye 416 | Elias Schmidt 417 | Elina Capel 418 | Elinore Cordoba 419 | Elizbeth Poll 420 | Ellie Jin 421 | Ellis Baskins 422 | Ellis Heckman 423 | Elly Miguez 424 | Ellyn Mahar 425 | Elmira Ohara 426 | Elmira Prall 427 | Elodia Gruner 428 | Elodia Mchargue 429 | Elsy Owenby 430 | Elva Penfield 431 | Elvia Rittenberry 432 | Elvie Enriguez 433 | Elvie Ryant 434 | Elyse Yingling 435 | Ema Ostler 436 | Emelia Camper 437 | Emelia Nye 438 | Emilee Carrick 439 | Emilee Stringham 440 | Emilia Wachter 441 | Emilio Matthews 442 | Emmett Lane 443 | Emmy Cedeno 444 | Enda Poissant 445 | Enid Novack 446 | Enrique Gonzales 447 | Era Gilstrap 448 | Erasmo Fellman 449 | Eric Rotenberry 450 | Erika Millner 451 | Erika Welty 452 | Erin Kyles 453 | Erlene Tibbetts 454 | Esmeralda Mishoe 455 | Estella Mccollom 456 | Ester Ayotte 457 | Esther Hollowell 458 | Estrella Oshaughnessy 459 | Ethel Castilla 460 | Ethel Greenwood 461 | Eufemia Hu 462 | Eufemia Rabon 463 | Eugene Collins 464 | Eula Stober 465 | Euna Salvo 466 | Eunice Prado 467 | Eura Schutt 468 | Evangelina Selders 469 | Evelia Mahi 470 | Evelyn Angel 471 | Evelynn Rockwell 472 | Evelynn Weatherhead 473 | Everett Ross 474 | Everette Profit 475 | Evita Hottle 476 | Exie Hinchman 477 | Exie Uribe 478 | Ezequiel Flicker 479 | FOUNTAIN FARM 480 | Fae Albanese 481 | Fannie Richardson 482 | Farrah Ingalls 483 | Fay Buttner 484 | Faye Huges 485 | Faye Oquendo 486 | Felipa Esqueda 487 | Felipa Shirkey 488 | Felipe Falgout 489 | Fernanda Steimle 490 | Fernande Debose 491 | Fernande Ganley 492 | Fidela Palazzolo 493 | Filomena Degregorio 494 | Florentino Noss 495 | Florine Bonk 496 | Florine Icenhour 497 | Florrie Willard 498 | Flossie Ledoux 499 | Floy Dollins 500 | Fran Cabezas 501 | Fran Charley 502 | Francesca Vo 503 | Francesco Brickman 504 | Francoise Mccreery 505 | Frederic Eleby 506 | Fredric Esteban 507 | Fumiko Connolly 508 | GAMBIA NEW MILLENIUM AIR COMPANY 509 | GOLDEN RESOURCES TRADING COMPANY L.L.C. 510 | GOWRIE FARM 511 | GRUPO CONSTRUCTOR SEGUNDO MILENIO, S.A. DE C.V. 512 | GRUPO FRACSA, S.A. DE C.V. 513 | Galen Wilde 514 | Garnett Coniglio 515 | Garret Monahan 516 | Garth Hudock 517 | Gary Kendall 518 | Gaynelle Boyer 519 | Gaynelle Emmerich 520 | Gemma Doutt 521 | Genevie Mcdevitt 522 | Geoffrey Page 523 | Georgene Brunelle 524 | Georgene Mccaul 525 | Georgiana Shear 526 | Georgina Tuley 527 | Gerald Darden 528 | Gerald Gatti 529 | Gerda Hord 530 | German Mcquillan 531 | Gertrude Dew 532 | Gertrudis Scudder 533 | Gertude Ouellette 534 | Gertude Resch 535 | Ghuma And'Rabbah 536 | Gia Mcgonigal 537 | Gidget Palumbo 538 | Gigi Stirling 539 | Gina Kitchell 540 | Giovanna Aguila 541 | Gisela Magnusson 542 | Gisela Quijas 543 | Giselle Roark 544 | Giuseppe Jawad 545 | Gladis Broe 546 | Glady Caul 547 | Glady Howery 548 | Glen Hartlage 549 | Glendora Ryerson 550 | Goldie Viger 551 | Gordon Arndt 552 | Grady Thoman 553 | Graig Bonn 554 | Granville Mizrahi 555 | Gretta Beane 556 | Grisel Lasso 557 | Guillermo Kimball 558 | Gwenda Ashlock 559 | HARMONY FARM 560 | HESONG TRADING CORPORATION 561 | Hank Doggett 562 | Hannibal Gaddafi 563 | Harold James 564 | Harvey Edelman 565 | Hassan Cheever 566 | Hattie Shellenberger 567 | Hattie Velasco 568 | Hayden Swindler 569 | Hazel Lefebure 570 | Heather Holland 571 | Heather Rieser 572 | Hedwig Studdard 573 | Helga Sherrick 574 | Hellen Gelinas 575 | Henrietta Tippens 576 | Heriberto Palmore 577 | Herminia Davies 578 | Hershel Galligan 579 | Herta Pucci 580 | Herta Singh 581 | Hilma Gioia 582 | Hoa Bayer 583 | Hope Frankel 584 | Horace King 585 | Howard Tropea 586 | Hsiu Vargas 587 | Humberto Arrowood 588 | Hung Bomba 589 | Hyo Deavers 590 | Hyo Demario 591 | IB OF AMERICA HOLDINGS INC. 592 | INMOBILIARIA PROMINENTE, S.A. DE C.V. 593 | IRAN & SHARGH COMPANY 594 | IRAN & SHARGH LEASING COMPANY 595 | IRBIS AIR COMPANY 596 | Ibrahim Mohamed Khalil 597 | Ida Liggett 598 | Iesha Cambridge 599 | Iesha Keely 600 | Ignacia Gorley 601 | Ileen Gallop 602 | Ilene Pedigo 603 | Iliana Kinzer 604 | Ilona Hermes 605 | Imogene Poplin 606 | In Lowy 607 | Inez Rodgers 608 | Inga Lemieux 609 | Ione Azcona 610 | Irena Clayborne 611 | Irma Lamb 612 | Isabel Hubbard 613 | Isabel Tongue 614 | Isabell Blann 615 | Isabell Charland 616 | Isabella Carlyle 617 | Isabelle Ponton 618 | Isaias Relyea 619 | Isis Siler 620 | Jacinto Echeverria 621 | Jacque Sellars 622 | Jade Stuhr 623 | Jaime Rencher 624 | Jalisa Hudgens 625 | Jamee Guida 626 | Jamee Hassan 627 | Jamison Greenhalgh 628 | Jammie Glines 629 | Jan Love 630 | Jana Clarke 631 | Janell Brumbaugh 632 | Janelle Hudson 633 | Janelle Im 634 | Janetta Fanelli 635 | Janis Straus 636 | Jannie Hesser 637 | Jared Gomez 638 | Jarred Knoblock 639 | Jayne Lavery 640 | Jayne Taunton 641 | Jayson Selig 642 | Jean Bernardo 643 | Jeane Strobel 644 | Jeanette Schuett 645 | Jeanie Lebeau 646 | Jeanie Titcomb 647 | Jeannette Norman 648 | Jenae Hartung 649 | Jenifer Blankenbaker 650 | Jeniffer Stark 651 | Jennette Weems 652 | Jennie Gorsuch 653 | Jennine Tekulve 654 | Jeremiah Phinney 655 | Jeremy Garner 656 | Jeri Battiste 657 | Jerica Joerling 658 | Jerilyn Kluth 659 | Jerlene Foss 660 | Jerlene Schmitmeyer 661 | Jermaine Keaton 662 | Jerome Parsons 663 | Jerry Bartlett 664 | Jesica Castellanos 665 | Jetta Byford 666 | Jettie Weast 667 | Joann Abril 668 | Joannie Roesch 669 | Jodee Ellisor 670 | Jodee Mateer 671 | Jodi Mcglamery 672 | Jodie Compos 673 | Joel Kuta 674 | Joella Mercedes 675 | Joelle Faires 676 | Joesph Poor 677 | John Gilmore 678 | Johnna Engstrom 679 | Johnnie Shortt 680 | Joi Engen 681 | Joleen Pardon 682 | Jolyn Friel 683 | Jolynn Ausmus 684 | Jona Nease 685 | Jonas Wesner 686 | Joni Cromley 687 | Joni Mundell 688 | Jonnie Powley 689 | Jonnie Shives 690 | Joselyn Regal 691 | Joseph Poole 692 | Josue Casillas 693 | Joy Barham 694 | Joy Statler 695 | Joye Camilleri 696 | Juan Cota 697 | Juana Sharma 698 | Jules Cisneros 699 | Jules Mcnab 700 | Julian Hill 701 | Juliane Taggert 702 | Julie Spurrier 703 | Junior Prock 704 | Junita Pasch 705 | KOREA COMPLEX EQUIPMENT IMPORT CORPORATION 706 | KOREA INTERNATIONAL CHEMICAL JOINT VENTURE COMPANY 707 | KOREA KWANGSONG TRADING CORPORATION 708 | KOREA PUGANG TRADING CORPORATION 709 | KOREA RYONGWANG TRADING CORPORATION 710 | KOREA RYONHA MACHINERY JOINT VENTURE CORPORATION 711 | Ka Hinkson 712 | Kai Hermosillo 713 | Kaitlin Fetterman 714 | Kaitlyn Sowell 715 | Kali Pyron 716 | Kalyn Kearney 717 | Kamchybek Asanbekovich Kolbayew 718 | Kandice Bailer 719 | Kanisha Flicker 720 | Karan Albus 721 | Karan Renfrew 722 | Karen Frappier 723 | Kari Aguilar 724 | Karima Albers 725 | Karima Klingensmith 726 | Karina Laughton 727 | Karla Ahner 728 | Karla Harper 729 | Karol Such 730 | Karoline Fogg 731 | Karolyn Dibernardo 732 | Karri Pierre 733 | Kassie Mcquillan 734 | Kassie Viruet 735 | Katelin Zurita 736 | Katharina Snuggs 737 | Katharine Ledezma 738 | Kathe Cronkhite 739 | Katherina Yuan 740 | Katherine Terpstra 741 | Katheryn Langston 742 | Kathleen Meserve 743 | Kathlyn Swigert 744 | Kathrin Leininger 745 | Kathryne Catledge 746 | Kati Kirkendoll 747 | Katie Landman 748 | Kattie Strickland 749 | Kay Kelly 750 | Kaycee Gamber 751 | Kayla Cannon 752 | Keeley Valdivia 753 | Keesha Tsosie 754 | Keiko Holtz 755 | Keith Bates 756 | Keith Galati 757 | Kellie Alejandro 758 | Kellye Spagnola 759 | Kelsey Relf 760 | Kelsie Wescott 761 | Kenya Plum 762 | Kerstin Ditzler 763 | Kesha Yerby 764 | Keva Walk 765 | Keven Mahaney 766 | Kim Higgins 767 | Kimberlie Burrowes 768 | Kimberlie Highfield 769 | Kirsten Hakala 770 | Kit Haug 771 | Kittie Gleason 772 | Kitty Arakaki 773 | Klara Summer 774 | Kortney Morel 775 | Kory Varela 776 | Kris Diemer 777 | Krista Bedoya 778 | Kristi Hibner 779 | Kristian Hermann 780 | Kristie Bynum 781 | Kristie Chi 782 | Kristina Loggins 783 | Kristina Ritz 784 | Kristyn Wroten 785 | Krystina Varden 786 | Kyle Morency 787 | Kyra Karp 788 | LOCHINVAR FARM 789 | LONGWOOD FARM 790 | LOTHAIN FARM 791 | Laci Coots 792 | Lakeisha Klug 793 | Lamonica Mcelwain 794 | Lana Gaylord 795 | Lana Plourde 796 | Lane Dufner 797 | Lane Lundin 798 | Lani Creasman 799 | Lannie Arens 800 | Lara Laning 801 | Lashaunda Browning 802 | Latarsha Fulmore 803 | Latia Napolitano 804 | Latonya Shellman 805 | Latosha Sax 806 | Latrice Goewey 807 | Latricia Sacks 808 | Launa Milbourn 809 | Laurena Rackley 810 | Laurette Violet 811 | Lavada Lamborn 812 | Lavenia Romanowski 813 | Lavon Greggs 814 | Lean Wire 815 | Leann Aikins 816 | Leann Kail 817 | Lecia Gossage 818 | Leena Donley 819 | Leia Gillan 820 | Leila Addison 821 | Lekisha Chavous 822 | Len Romero 823 | Lena Comacho 824 | Lena Fuller 825 | Leo Bomar 826 | Leonard Galeano 827 | Leonel Spradley 828 | Leonor Ahn 829 | Leopoldo Woolbright 830 | Lesley Pettit 831 | Leslie Vanduyn 832 | Lessie Derosier 833 | Lessie Plewa 834 | Leticia Burgess 835 | Letisha Niles 836 | Lexie Wilmore 837 | Lezlie Menjivar 838 | Liane Waterfield 839 | Librada Heineman 840 | Lien Matley 841 | Lillia Ramon 842 | Lillian Murdock 843 | Lillie Blake 844 | Lilly Vandermeulen 845 | Lincoln Scipio 846 | Linda Hansen 847 | Lindsay Furlong 848 | Lindsey Brackman 849 | Lindsey Stowell 850 | Ling Kerekes 851 | Linwood Boyden 852 | Lisa Lorance 853 | Lisabeth Patricia 854 | Lise Rampton 855 | Liza Brokaw 856 | Lizabeth Mayor 857 | Lizabeth Winsett 858 | Lola Geronimo 859 | Lola Lepine 860 | Lon Shafer 861 | Lonnie Lally 862 | Loralee Goodlow 863 | Loreen Raysor 864 | Lorelei Ruis 865 | Lorene Vanburen 866 | Lori Ropp 867 | Loria Nasser 868 | Lorinda Anglin 869 | Lorine Engelke 870 | Loris Hitchman 871 | Lorna Lovin 872 | Lorraine Wiltsie 873 | Lottie Mccrystal 874 | Lou Wyrick 875 | Louisa Norgard 876 | Lourdes Kellems 877 | Louvenia Lukens 878 | Loyd Demoss 879 | Luana Dowdle 880 | Lucas Eargle 881 | Lucinda Alexander 882 | Lucio Loftus 883 | Ludie Rook 884 | Luella Sawyer 885 | Luetta Mcclenton 886 | Luis Franklin 887 | Luise Kozel 888 | Luke Figueroa 889 | Lulu Clements 890 | Luther Chambers 891 | Luvenia Lundahl 892 | Lynda Maust 893 | Lyndsey Dolloff 894 | MARANGE RESOURCES (PRIVATE) LIMITED 895 | MARONDERA MAPLE LEAF FARM 896 | MBADA DIAMONDS (PRIVATE) LIMITED 897 | MCS ENGINEERING 898 | MCS INTERNATIONAL GMBH 899 | MELLAT INSURANCE COMPANY 900 | MODABER 901 | MOLDTRANSAVIA SRL 902 | Ma Okane 903 | Machelle Benes 904 | Macie Marois 905 | Mack Soucy 906 | Maddie Benally 907 | Madelene Delillo 908 | Madeline Hannah 909 | Madelyn Vashon 910 | Madlyn Pittard 911 | Mafalda Joaquin 912 | Magaly Ange 913 | Maggie Beaubien 914 | Maida Goodpaster 915 | Maida Syed 916 | Malisa Ezell 917 | Mallory Blystone 918 | Man Davilla 919 | Manual Finneran 920 | Manual Shao 921 | Maranda Kern 922 | Marc Mcclain 923 | Marcela Herbert 924 | Marcelina Newlin 925 | Marcelle Rhee 926 | Marg Salinas 927 | Margaret Cruz 928 | Margaret Mick 929 | Margarette Lucy 930 | Margery Jewett 931 | Margit Sober 932 | Margorie Acre 933 | Margot Bruhn 934 | Marguerita Racine 935 | Marguerite Yahn 936 | Marhta Franke 937 | Mariana Weatherholtz 938 | Marianna Stjacques 939 | Maricruz Tassin 940 | Mariela Bones 941 | Marietta Bugbee 942 | Marilyn Root 943 | Marinda Leavens 944 | Mario Hightower 945 | Mario Kanne 946 | Marisa Kingsland 947 | Marlana Gartrell 948 | Marleen Gainer 949 | Marlen Cyr 950 | Marlen Doshier 951 | Marlen Gregory 952 | Marlin Chunn 953 | Marlin Housel 954 | Marlin Miesner 955 | Marnie Verne 956 | Marquita Reck 957 | Marquitta Anker 958 | Marry Bradley 959 | Marshall Freeland 960 | Marshall Horsey 961 | Marshall Spece 962 | Marta Schutte 963 | Martine Haislip 964 | Marty Minjarez 965 | Mary Carpenter 966 | Maryanna Kerrigan 967 | Maryanna Loera 968 | Maryjane Cracraft 969 | Maryjo Twine 970 | Marylou Matlock 971 | Marylyn Knicely 972 | Maryrose Isherwood 973 | Matha Fey 974 | Mathew Joachim 975 | Mathilde Mcnaughton 976 | Matuq Mohammed Matuq 977 | Maud Goldberger 978 | Maureen Kilman 979 | Maxie Byfield 980 | Maxima Bachus 981 | Maybell Aldape 982 | Mayme Nevarez 983 | Maynard Wysocki 984 | Mayola Mccallon 985 | Mckinley Blom 986 | Meghan Pangburn 987 | Meghann Brezinski 988 | Mei Delman 989 | Melani Blundell 990 | Melina Karr 991 | Melony Eichelberger 992 | Melvin Vanburen 993 | Meredith Hauge 994 | Meri Eury 995 | Meri Morley 996 | Meridith Arends 997 | Merle Freeman 998 | Merlin Mai 999 | Merlyn Bauman 1000 | Mi Clinton 1001 | Mi Kneeland 1002 | Mi Reiter 1003 | Michale Iadarola 1004 | Michele Garcia 1005 | Miesha James 1006 | Mikaela Gaymon 1007 | Miki Lally 1008 | Mila Moretz 1009 | Milagros Corlew 1010 | Milly Judon 1011 | Milton Bade 1012 | Mina Suriel 1013 | Minh Spurlock 1014 | Miquel Redden 1015 | Miquel Thibeaux 1016 | Mira Konopka 1017 | Miranda Hohn 1018 | Mireille Knox 1019 | Miss Sokol 1020 | Mistie Killgore 1021 | Mitch Venable 1022 | Mitch Vieira 1023 | Mitchell Deland 1024 | Mitsue Pinnock 1025 | Mohammad Charboneau 1026 | Mollie Lacroix 1027 | Morris Miles 1028 | Mose Weyandt 1029 | Moshe Leisy 1030 | Mozella Stott 1031 | Mozelle Ehrlich 1032 | Muhammad Gaddafi 1033 | Myra Curtis 1034 | Myrna Schroth 1035 | Myrtle Fitzgerald 1036 | NDLOVU MOTORWAYS 1037 | NORDIC LTD. 1038 | Nadene Benzing 1039 | Nadene Fodor 1040 | Nadine Parker 1041 | Nadine Slevin 1042 | Nakesha Liang 1043 | Nam Witt 1044 | Nan Iliff 1045 | Nana Boyter 1046 | Nancy Myricks 1047 | Nancy Silvis 1048 | Nanette Northrop 1049 | Nannette Bellone 1050 | Nannie Statton 1051 | Napoleon Dorsett 1052 | Natalie Balli 1053 | Natashia Stanfield 1054 | Neal Wehner 1055 | Nedra Corchado 1056 | Neida Harring 1057 | Nellie Colon 1058 | Nellie Langone 1059 | Neoma Preston 1060 | Neta Fergus 1061 | Neville Vanover 1062 | Nguyet Featherston 1063 | Nia Nadal 1064 | Nick Trapp 1065 | Nicolas Barnett 1066 | Nicolette Sutphin 1067 | Nicolle Molock 1068 | Nida Infantino 1069 | Nida Jumper 1070 | Niesha Munro 1071 | Nilda Haight 1072 | Noel Cairns 1073 | Noelle Costa 1074 | Nohemi Schriver 1075 | Norene Ang 1076 | Nu Portman 1077 | ODESSA AIR 1078 | OLDHAM FARM 1079 | OMID REY CIVIL & CONSTRUCTION COMPANY 1080 | ORIENT STAR CORPORATION 1081 | Octavia Good 1082 | Octavia Overcash 1083 | Odilia Vitale 1084 | Ofelia Haapala 1085 | Ola Power 1086 | Olimpia Pawlak 1087 | Olin Coomer 1088 | Oma Crutcher 1089 | Oneida Grover 1090 | Orville Haar 1091 | Osvaldo Thornsberry 1092 | Otilia Decola 1093 | Owen Maresca 1094 | Ozella Cavallaro 1095 | PARDIS INVESTMENT COMPANY 1096 | PETRO LONDON, S. DE R.L. DE C.V. 1097 | PETRO MAS, S. DE R.L. DE C.V. 1098 | PIMENTO FARM 1099 | PISCILANEA, S.A. DE C.V. 1100 | PROMI FEL, S. DE R.L. DE C.V. 1101 | Paige Burkhead 1102 | Paige Herzog 1103 | Pamala Marsden 1104 | Pamela Joyner 1105 | Paola Villalta 1106 | Parthenia Gries 1107 | Particia Ferrante 1108 | Patria Boyer 1109 | Patrica Josey 1110 | Patsy Faz 1111 | Patti Hines 1112 | Paulette Thornton 1113 | Paulina Matsumoto 1114 | Pedro Roldan 1115 | Peggie Easler 1116 | Peggy Borunda 1117 | Pei Christian 1118 | Peter Dineen 1119 | Phil Hopkins 1120 | Phil Stalling 1121 | Philip Henderson 1122 | Ping Fujimoto 1123 | Piper Cayetano 1124 | Providencia Styles 1125 | Qiana Connally 1126 | Quincy Cupp 1127 | Quincy Macrae 1128 | Quincy Racette 1129 | Quinn Clingan 1130 | Quintin Elmendorf 1131 | Quinton Fox 1132 | R/E OF AUDREY FARM 1133 | R/E OF MLEMBWE FARM 1134 | RESTAURANT BAR LOS ANDARIEGOS, S.A. DE C.V. 1135 | REY INVESTMENT COMPANY 1136 | REYCO GMBH. 1137 | RICHARD A. CHICHAKLI PC 1138 | RISHMAK PRODUCTIVE & EXPORTS COMPANY 1139 | ROCKMAN LTD. 1140 | Rachel Fisher 1141 | Rachelle Scrivens 1142 | Racquel Master 1143 | Racquel Sattler 1144 | Rafael Jefferson 1145 | Rafik Mohamad Yousef 1146 | Raisa Vandeventer 1147 | Ralph Cedeno 1148 | Rana Westra 1149 | Randall Madson 1150 | Randall Sayers 1151 | Raphael Thorsen 1152 | Raul Fleetwood 1153 | Ray Miera 1154 | Raye Stenzel 1155 | Rayford Tapscott 1156 | Raymond Barrett 1157 | Raymond Lux 1158 | Raymond Myatt 1159 | Rayna Felter 1160 | Rayna Sampsell 1161 | Rebbeca Vineyard 1162 | Regena Steier 1163 | Reginia Cortes 1164 | Reid Bickers 1165 | Reid Hyndman 1166 | Reina Alberson 1167 | Reina Poff 1168 | Reinaldo Soderberg 1169 | Reita Lindo 1170 | Remona Benninger 1171 | Remona Gullette 1172 | Remona Landaverde 1173 | Renee Townsend 1174 | Renna Bookman 1175 | Retha Crater 1176 | Reva Willey 1177 | Rex Wesley 1178 | Rhoda Heyer 1179 | Rhoda Ormond 1180 | Richard Hayes 1181 | Rickey Flores 1182 | Ricky Koepsell 1183 | Rima Farwell 1184 | Rima Meadors 1185 | Rivka Kehr 1186 | Robbie Drost 1187 | Robby Mckinnie 1188 | Rochel Demers 1189 | Rochel Krause 1190 | Rocio Doom 1191 | Rodney Kershner 1192 | Rodolfo Hazelton 1193 | Rolanda Debellis 1194 | Rolanda Kreider 1195 | Rolanda Marriner 1196 | Ron Farnum 1197 | Rona Moulton 1198 | Rosalia Penrose 1199 | Rosalinda Meals 1200 | Rosamaria Bibbs 1201 | Roseann Booher 1202 | Roseann Frierson 1203 | Roseanna Weil 1204 | Roseanne Anselmo 1205 | Roselee Dandy 1206 | Rosena Giraldo 1207 | Rosena Montero 1208 | Rosenda Tilson 1209 | Roslyn Deckman 1210 | Ross Medlen 1211 | Rossie Singleterry 1212 | Roxana Alt 1213 | Roxane Holliman 1214 | Roxie Spieker 1215 | Roxy Gertsch 1216 | Rudolph Stransky 1217 | Rueben Fouch 1218 | Rusty Briski 1219 | Rusty Klein 1220 | Ryan Kitson 1221 | SAN AIR GENERAL TRADING FZE 1222 | SANTA CRUZ IMPERIAL AIRLINES 1223 | SERVICIO Y OPERADORA SANTA ANA, S.A. DE C.V. 1224 | SOUTHBOUND LTD. 1225 | SPRING SP FARM 1226 | SYRIAN AIR FORCE INTELLIGENCE 1227 | SYRIAN MILITARY INTELLIGENCE 1228 | SYRIAN NATIONAL SECURITY BUREAU 1229 | Saadi Gaddafi 1230 | Sabina Privette 1231 | Sabine Stelly 1232 | Sabrina Shahid 1233 | Sadie Martinez 1234 | Sadye Heidenreich 1235 | Sadye Shott 1236 | Safia Farkash 1237 | Saif Al-Arab Gaddafi 1238 | Sajid Mohammed Badat 1239 | Sal Munz 1240 | Salley Zenon 1241 | Samantha Chute 1242 | Samara Neher 1243 | Samira Stocking 1244 | Sammy Wheeler 1245 | Samual Groh 1246 | Sandi Hoopes 1247 | Sanora Polk 1248 | Santana Holte 1249 | Santiago Reese 1250 | Santos Hadnot 1251 | Saran Kingrey 1252 | Sari Busey 1253 | Sasha Bona 1254 | Sasha Layfield 1255 | Sasha Mckenney 1256 | Savannah Morfin 1257 | Scot Stlawrence 1258 | Sean Bragan 1259 | Sean Weaver 1260 | Seema Carcamo 1261 | Serita Migliore 1262 | Shalanda Linson 1263 | Shalon Dutil 1264 | Shanae Roepke 1265 | Shanel Albury 1266 | Shanel Lavine 1267 | Shantelle Liberatore 1268 | Shanti Briant 1269 | Sharee Hoppe 1270 | Sharice Jeter 1271 | Sharla Saenz 1272 | Sharon Claycomb 1273 | Sharron Mash 1274 | Shaun Munyon 1275 | Shauna Garst 1276 | Shavon Levron 1277 | Shawanda Thaler 1278 | Shawna Sheppard 1279 | Shawna Sorrels 1280 | Shawnna Deeds 1281 | Shayne Moreau 1282 | Sheila Hodges 1283 | Sheilah Kindell 1284 | Shela Karns 1285 | Shelton Copper 1286 | Sherie Rodriguz 1287 | Sherley Markowitz 1288 | Sherly Foraker 1289 | Sherrell Watkins 1290 | Sherron Rosenberger 1291 | Sherwood Mason 1292 | Shirl Stumbo 1293 | Shirlee Haskin 1294 | Shizuko Blais 1295 | Shizuko Faller 1296 | Shon Denbow 1297 | Shoshana Chauncey 1298 | Shoshana Golston 1299 | Sid Armand 1300 | Sid Rule 1301 | Siobhan Gammon 1302 | Sirena Cothran 1303 | Slyvia Factor 1304 | Solomon Blanchard 1305 | Stacy Camire 1306 | Stan Shelman 1307 | Stanley Lamers 1308 | Stefania Koster 1309 | Stefanie Surles 1310 | Stephan Bridgers 1311 | Stephani Umstead 1312 | Stephen Millet 1313 | Stephen Schacherer 1314 | Steven Langford 1315 | Summer Schieber 1316 | Susana Kloss 1317 | Susannah Patenaude 1318 | Susie Sturgis 1319 | Suzann Dewoody 1320 | Suzann Sessions 1321 | Suzanne Husain 1322 | Suzi Mcneel 1323 | TADBIR BROKERAGE COMPANY 1324 | TADBIR CONSTRUCTION DEVELOPMENT COMPANY 1325 | TADBIR ECONOMIC DEVELOPMENT GROUP 1326 | TADBIR ENERGY DEVELOPMENT GROUP CO. 1327 | TADBIR INVESTMENT COMPANY 1328 | TAXI AEREO NACIONAL DE CULIACAN, S.A. 1329 | TOSEE EQTESAD AYANDEHSAZAN COMPANY 1330 | TOSONG TECHNOLOGY TRADING CORPORATION 1331 | TRANS AVIATION GLOBAL GROUP INC. 1332 | Tabitha Eriksen 1333 | Tabitha Larson 1334 | Tahir Nasuf 1335 | Tai Maus 1336 | Tajuana Farlow 1337 | Tajuana Hunsaker 1338 | Talia Gaitan 1339 | Talia Gamino 1340 | Tam Cola 1341 | Tamara Dedman 1342 | Tammera Mestas 1343 | Tammie Macpherson 1344 | Taneka Plumber 1345 | Tanisha Mcshane 1346 | Tanja Tarbox 1347 | Tara Mcguire 1348 | Tarah Renwick 1349 | Taren Pusey 1350 | Tari Carstarphen 1351 | Tarra Denmon 1352 | Tatum Weimer 1353 | Tayna Mossman 1354 | Tayna Pakele 1355 | Temeka Olivares 1356 | Tempie Costello 1357 | Tempie Gabrielson 1358 | Tena Ardis 1359 | Tenesha Reichert 1360 | Tennille Licon 1361 | Teresa Wada 1362 | Terisa Frisch 1363 | Terrence Greaver 1364 | Terrence Wise 1365 | Terresa Klassen 1366 | Terry Hogan 1367 | Thalia Paine 1368 | Thanh Kirsh 1369 | Thelma Collar 1370 | Theodora Veasley 1371 | Theodore Wright 1372 | Therese Dye 1373 | Therese Gearing 1374 | Theressa Cabello 1375 | Thi Hilger 1376 | Tiana Fazio 1377 | Tiara Osorio 1378 | Tiera Hassler 1379 | Tiera Markus 1380 | Tifany Cornell 1381 | Tiffani Lozada 1382 | Tiffanie Boozer 1383 | Tisa Rolls 1384 | Tobie Amend 1385 | Tomas Dubiel 1386 | Tomas Griffin 1387 | Tomeka Bolden 1388 | Tomeka Mcwain 1389 | Tomika Gates 1390 | Tomiko Doetsch 1391 | Tommy Rivera 1392 | Tonette Poovey 1393 | Tonie Pier 1394 | Tonita Marti 1395 | Tonja Rinehart 1396 | Tony Garibay 1397 | Toshia Barkan 1398 | Tracee Averitt 1399 | Trang Thomas 1400 | Treasa Fryer 1401 | Treena Man 1402 | Trevor Platz 1403 | Trey Hung 1404 | Trista Rahman 1405 | Twana Falkner 1406 | Tyson Reaux 1407 | ULVA FARM 1408 | UMGUZA BLOCK FARM 1409 | VILLAS DEL COLLI S.A. DE C.V. 1410 | Valene Longerbeam 1411 | Valentin Gerlach 1412 | Valerie Soto 1413 | Valery Shuey 1414 | Vallie Ping 1415 | Vallie Sweat 1416 | Van Balla 1417 | Vashti Tew 1418 | Velma Hawkins 1419 | Velva Ehrman 1420 | Vena Riter 1421 | Vena Stubbs 1422 | Venetta Borchers 1423 | Venus Datta 1424 | Vera Fryer 1425 | Verena Horowitz 1426 | Verline Bautista 1427 | Verna Boyd 1428 | Vernie Boger 1429 | Vertie Manzi 1430 | Vesta Sylvest 1431 | Veta Laguardia 1432 | Vickie Parton 1433 | Vicky Donadio 1434 | Victor Mcgee 1435 | Victorina Grillo 1436 | Vina Walck 1437 | Vincenza Henkle 1438 | Viola Phelps 1439 | Viola Procter 1440 | Viva Stivers 1441 | Vivian Moody 1442 | Von Unsworth 1443 | Vonda Schlabach 1444 | Wanda Greenough 1445 | Wanita Wait 1446 | Warren Perez 1447 | Waylon Hoff 1448 | Wei Demaio 1449 | Weldon Newberg 1450 | Wendell Nelson 1451 | Wendell Ulman 1452 | Wesley Panek 1453 | Wesley Teamer 1454 | Weston Canning 1455 | Weston Ealey 1456 | Weston Haynie 1457 | Whitney Grimaldi 1458 | Wilber Obermiller 1459 | Wilbert Murphy 1460 | Wilfred Cartwright 1461 | William Glover 1462 | Williams Armitage 1463 | Willie Castleman 1464 | Willie Mack 1465 | Willow Goldenberg 1466 | Windy Ferrer 1467 | Winford Roller 1468 | Winnifred Swearingen 1469 | Wynona Obryant 1470 | Xenia Gaulding 1471 | YK-AQA 1472 | YK-AQB 1473 | YK-AQD 1474 | YK-AQE 1475 | YK-AQF 1476 | YK-AQG 1477 | YK-AYA 1478 | YK-AYB 1479 | YK-AYC 1480 | YK-AYD 1481 | YK-AYE 1482 | YK-AYF 1483 | Yasser Abu 1484 | Yer Lohse 1485 | Yevette Clendenin 1486 | Yoko Guebert 1487 | Yolando Droz 1488 | Yuk Hornyak 1489 | Yung Roda 1490 | Yuri Boyster 1491 | ZARIN RAFSANJAN CEMENT COMPANY 1492 | Zachariah Galyon 1493 | Zachariah Leeson 1494 | Zada Tison 1495 | Zelma Bluhm 1496 | Zenobia Chouinard 1497 | Zola Cearley 1498 | Zulma Armbruster 1499 | Zulma Bolton 1500 | Zulma Colger -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/webapp/WEB-INF/spring/webmvc-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/webapp/WEB-INF/views/home.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spring Batch Samples - scalability 5 | 6 | 7 | 8 | 70 | 71 | 72 | 73 |
74 | Output file path: 75 | Number of transactions: 76 | 77 | 78 |
79 | 80 |
81 | Input file path: 82 | Scaling strategy: 83 | 89 | 90 | 91 |
92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | contextConfigLocation 10 | classpath*:META-INF/spring/applicationContext.xml 11 | 12 | 13 | 14 | spring.profiles.active 15 | prod 16 | 17 | 18 | 19 | org.springframework.web.context.ContextLoaderListener 20 | 21 | 22 | 23 | dispatcher-servlet 24 | org.springframework.web.servlet.DispatcherServlet 25 | 26 | contextConfigLocation 27 | /WEB-INF/spring/webmvc-config.xml 28 | 29 | 1 30 | true 31 | 32 | 33 | 34 | dispatcher-servlet 35 | / 36 | 37 | 38 | 39 | My DataSource Reference 40 | jdbc/DS 41 | javax.sql.DataSource 42 | Container 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/java/com/ontheserverside/batch/bank/job/Elixir0LoadStepTest.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.job; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | import com.ontheserverside.batch.bank.tx.TransactionStatus; 5 | import org.hibernate.SessionFactory; 6 | import org.hibernate.criterion.Order; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.batch.core.*; 10 | import org.springframework.batch.test.JobLauncherTestUtils; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.ComponentScan; 14 | import org.springframework.context.annotation.Configuration; 15 | import org.springframework.context.annotation.ImportResource; 16 | import org.springframework.core.task.TaskExecutor; 17 | import org.springframework.integration.Message; 18 | import org.springframework.integration.MessageChannel; 19 | import org.springframework.integration.channel.AbstractPollableChannel; 20 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 21 | import org.springframework.test.context.ActiveProfiles; 22 | import org.springframework.test.context.ContextConfiguration; 23 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 24 | 25 | import java.math.BigDecimal; 26 | import java.text.SimpleDateFormat; 27 | import java.util.List; 28 | 29 | import static org.hamcrest.CoreMatchers.is; 30 | import static org.junit.Assert.assertThat; 31 | 32 | @RunWith(SpringJUnit4ClassRunner.class) 33 | @ContextConfiguration 34 | @ActiveProfiles("test") 35 | public class Elixir0LoadStepTest { 36 | 37 | @Configuration 38 | @ComponentScan("com.ontheserverside.batch.bank") 39 | @ImportResource({ "classpath:/META-INF/spring/hibernateContext.xml", 40 | "classpath:/META-INF/spring/batchContext.xml" }) 41 | static class ApplicationContext { 42 | @Bean 43 | public JobLauncherTestUtils jobLauncherTestUtils() { 44 | return new JobLauncherTestUtils(); 45 | } 46 | 47 | @Bean 48 | public TaskExecutor executor() { 49 | return new ThreadPoolTaskExecutor(); 50 | } 51 | 52 | @Bean(name = { "screening.requests.partitioning", 53 | "screening.replies.partitioning"}) 54 | public MessageChannel channels() { 55 | return new AbstractPollableChannel() { 56 | @Override 57 | protected Message doReceive(long timeout) { 58 | throw new UnsupportedOperationException("I'm just mocked test channel"); 59 | } 60 | 61 | @Override 62 | protected boolean doSend(Message message, long timeout) { 63 | throw new UnsupportedOperationException("I'm just mocked test channel"); 64 | } 65 | }; 66 | } 67 | } 68 | 69 | @Autowired 70 | private JobLauncherTestUtils jobLauncherTestUtils; 71 | 72 | @Autowired 73 | private SessionFactory sessionFactory; 74 | 75 | @Test 76 | public void shouldLoadElixir0TxFromFile() throws Exception { 77 | final JobParameters jobParameters = new JobParametersBuilder() 78 | .addString("inputFile", this.getClass().getResource("/elixir0/5Tx.elixir0").getPath()) 79 | .toJobParameters(); 80 | 81 | final JobExecution jobExecution = jobLauncherTestUtils.launchStep("elixir0LoadStep", jobParameters); 82 | 83 | final StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next(); 84 | assertThat(stepExecution.getExitStatus(), is(ExitStatus.COMPLETED)); 85 | assertThat(stepExecution.getStatus(), is(BatchStatus.COMPLETED)); 86 | assertThat(stepExecution.getReadCount(), is(5)); // 5 is a number of TX in the imported file 87 | assertThat(stepExecution.getWriteCount(), is(5)); 88 | 89 | final List importedTransactions = 90 | sessionFactory.openSession() 91 | .createCriteria(Elixir0Transaction.class) 92 | .addOrder(Order.asc("paymentDate")) 93 | .list(); 94 | assertThat(importedTransactions.size(), is(5)); 95 | 96 | // we'll test mapping of the representative transaction, the rest can be proved by induction ;-) 97 | final Elixir0Transaction transaction = importedTransactions.get(0); 98 | assertThat(transaction.getStatus(), is(TransactionStatus.LOADED)); 99 | assertThat(transaction.getPaymentCode(), is(110)); 100 | assertThat(transaction.getPaymentDate().getTime(), is(new SimpleDateFormat("yyyyMMdd").parse("20140212").getTime())); 101 | assertThat(transaction.getAmount().compareTo(BigDecimal.valueOf(828749700184127L)), is(0)); 102 | assertThat(transaction.getOrderingPartySortCode(), is("68578953")); 103 | assertThat(transaction.getOrderingPartyAccountNumber(), is("87685789534046696210183491")); 104 | assertThat(transaction.getBeneficiaryAccountNumber(), is("81878754069967016032059101")); 105 | assertThat(transaction.getOrderingPartyName(), is("SOUTHBOUND LTD.")); 106 | assertThat(transaction.getOrderingPartyAddress(), is("8876 Harvest Leaf Harbour, Fighting Rock Corner, Maryland, 21069-9972, US")); 107 | assertThat(transaction.getBeneficiaryName(), is("Vincenza Henkle")); 108 | assertThat(transaction.getBeneficiaryAddress(), is("4489 Sunny Hickory Terrace, Enderby, Iowa, 50157-9431, US")); 109 | assertThat(transaction.getBeneficiarySortCode(), is("87875406")); 110 | assertThat(transaction.getPaymentDetails(), is("passkey deleaves rimmed sarsens sponsor")); 111 | assertThat(transaction.getTransactionCode(), is("51")); 112 | assertThat(transaction.getClientBankInformation(), is("")); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/java/com/ontheserverside/batch/bank/processing/JobParameterExecutionDeciderTest.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.springframework.batch.core.JobExecution; 6 | import org.springframework.batch.core.JobParameters; 7 | import org.springframework.batch.core.JobParametersBuilder; 8 | import org.springframework.batch.core.StepExecution; 9 | import org.springframework.batch.core.job.flow.FlowExecutionStatus; 10 | 11 | import static org.hamcrest.CoreMatchers.is; 12 | import static org.hamcrest.CoreMatchers.not; 13 | import static org.hamcrest.CoreMatchers.nullValue; 14 | import static org.junit.Assert.assertThat; 15 | 16 | public class JobParameterExecutionDeciderTest { 17 | 18 | private static final String JOB_PARAMETER_KEY = "someFancyKey"; 19 | 20 | private JobParameterExecutionDecider decider; 21 | 22 | @Before 23 | public void setUp() { 24 | this.decider = new JobParameterExecutionDecider(); 25 | decider.setJobParameterKey(JOB_PARAMETER_KEY); 26 | } 27 | 28 | @Test 29 | public void shouldReturnFlowStatusFromJobParameter() { 30 | JobParameters jobParameters = new JobParametersBuilder() 31 | .addString(JOB_PARAMETER_KEY, "PUFF") 32 | .toJobParameters(); 33 | 34 | JobExecution jobExecution = new JobExecution(1L, jobParameters); 35 | StepExecution stepExecution = new StepExecution("myStep", jobExecution); 36 | 37 | final FlowExecutionStatus flowExecutionStatus = decider.decide(jobExecution, stepExecution); 38 | 39 | assertThat(flowExecutionStatus, is(not(nullValue()))); 40 | assertThat(flowExecutionStatus, is(new FlowExecutionStatus("PUFF"))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/java/com/ontheserverside/batch/bank/processing/ModuloPartitionerTest.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.processing; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.springframework.batch.item.ExecutionContext; 6 | 7 | import java.util.Map; 8 | 9 | import static org.hamcrest.CoreMatchers.is; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.hamcrest.CoreMatchers.nullValue; 12 | import static org.junit.Assert.assertThat; 13 | 14 | public class ModuloPartitionerTest { 15 | 16 | private ModuloPartitioner partitioner; 17 | 18 | @Before 19 | public void setUp() { 20 | this.partitioner = new ModuloPartitioner(); 21 | } 22 | 23 | @Test 24 | public void shouldProduceNoContextspForZeroSizeGrid() { 25 | Map map = partitioner.partition(0); 26 | 27 | assertThat(map, is(not(nullValue()))); 28 | assertThat(map.isEmpty(), is(true)); 29 | } 30 | 31 | @Test 32 | public void shouldProduceContextsForNonEmptyGrid() { 33 | Map map = partitioner.partition(3); 34 | 35 | assertThat(map, is(not(nullValue()))); 36 | assertThat(map.size(), is(3)); 37 | 38 | ExecutionContext context0 = map.get("partition-0"); 39 | ExecutionContext context1 = map.get("partition-1"); 40 | ExecutionContext context2 = map.get("partition-2"); 41 | 42 | assertThat(context0, is(not(nullValue()))); 43 | assertThat(context1, is(not(nullValue()))); 44 | assertThat(context2, is(not(nullValue()))); 45 | 46 | assertThat((int) context0.get(ModuloPartitioner.MOD_REMAINDER_KEY), is(0)); 47 | assertThat((int) context1.get(ModuloPartitioner.MOD_REMAINDER_KEY), is(1)); 48 | assertThat((int) context2.get(ModuloPartitioner.MOD_REMAINDER_KEY), is(2)); 49 | 50 | assertThat((int) context0.get(ModuloPartitioner.MOD_DIVISOR_KEY), is(3)); 51 | assertThat((int) context1.get(ModuloPartitioner.MOD_DIVISOR_KEY), is(3)); 52 | assertThat((int) context2.get(ModuloPartitioner.MOD_DIVISOR_KEY), is(3)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/java/com/ontheserverside/batch/bank/screening/JaroBagFuzzyMatcherTest.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.CoreMatchers.is; 6 | import static org.junit.Assert.assertThat; 7 | 8 | /** 9 | * Group of tests used to adjust sensitivity factors of metrics - we don't want to test framework here, huh? ;) 10 | */ 11 | public class JaroBagFuzzyMatcherTest { 12 | 13 | private JaroBagFuzzyMatcher matcher = new JaroBagFuzzyMatcher(); 14 | 15 | @Test 16 | public void shouldNotConsiderWordsOrder() { 17 | assertThat(matcher.sequencesMatching("conan the conqueror", "the conqueror conan"), is(true)); 18 | } 19 | 20 | @Test 21 | public void shouldBeCaseInsensitive() { 22 | assertThat(matcher.sequencesMatching("john rambo", "JOHN RAMBO"), is(true)); 23 | } 24 | 25 | @Test 26 | public void shouldMatchForOneLetterTypos() { 27 | assertThat(matcher.sequencesMatching("jovn rambo", "john rambo"), is(true)); 28 | assertThat(matcher.sequencesMatching("john rampo", "john rambo"), is(true)); 29 | } 30 | 31 | @Test 32 | public void shouldMatchForOneLetterMissing() { 33 | assertThat(matcher.sequencesMatching("conan the onqueror", "conan the conqueror"), is(true)); 34 | assertThat(matcher.sequencesMatching("coan the conqueror", "conan the conqueror"), is(true)); 35 | } 36 | 37 | @Test 38 | public void shouldMatchForOneLetterAdded() { 39 | assertThat(matcher.sequencesMatching("terrorist", "terroristt"), is(true)); 40 | assertThat(matcher.sequencesMatching("bomb", "bombb"), is(true)); 41 | assertThat(matcher.sequencesMatching("my new gun", "my new gunn"), is(true)); 42 | assertThat(matcher.sequencesMatching("gun", "gunn"), is(true)); 43 | } 44 | 45 | @Test 46 | public void shouldMatchForOneLetterMisplaced() { 47 | assertThat(matcher.sequencesMatching("conna the conqueror", "conan the conqueror"), is(true)); 48 | assertThat(matcher.sequencesMatching("conan the ocnqueror", "conan the conqueror"), is(true)); 49 | } 50 | 51 | @Test 52 | public void shouldMatchForOneLetterTypoAndDifferentWordsOrder() { 53 | assertThat(matcher.sequencesMatching("rambo jovn", "john rambo"), is(true)); 54 | assertThat(matcher.sequencesMatching("rampo john", "john rambo"), is(true)); 55 | } 56 | 57 | @Test 58 | public void shouldMatchForOneLetterMissingAndDifferentWordsOrder() { 59 | assertThat(matcher.sequencesMatching("the brbarian conan", "conan the barbarian"), is(true)); 60 | assertThat(matcher.sequencesMatching("barbarian conan th", "conan the barbarian"), is(true)); 61 | } 62 | 63 | @Test 64 | public void shouldMatchForOneLetterMisplacedAndDifferentWordsOrder() { 65 | assertThat(matcher.sequencesMatching("the cnoan conqueror", "conan the conqueror"), is(true)); 66 | assertThat(matcher.sequencesMatching("conan ocnqueror the", "conan the conqueror"), is(true)); 67 | } 68 | 69 | @Test 70 | public void shouldNotMatchForDifferentWords() { 71 | // it's hard do define what "different words" are in terms of fuzzy matching; 72 | // this test (as well as all others within this class) should be considered just 73 | // as a way to adjust sensitivity factors of metrics 74 | assertThat(matcher.sequencesMatching("bombai", "bomb"), is(false)); 75 | assertThat(matcher.sequencesMatching("attack", "attention"), is(false)); 76 | assertThat(matcher.sequencesMatching("taliban", "talisman"), is(false)); 77 | assertThat(matcher.sequencesMatching("nuclear", "uncle"), is(false)); 78 | assertThat(matcher.sequencesMatching("gun", "gunner"), is(false)); 79 | assertThat(matcher.sequencesMatching("uranium", "uranus"), is(false)); 80 | assertThat(matcher.sequencesMatching("matshalaga", "matha"), is(false)); 81 | } 82 | 83 | @Test 84 | public void shouldNotMatchForDifferentWordPhrases() { 85 | // just like in case of the test above, it's hard to define what "different phrases" 86 | // means in terms of fuzzy matching; this test should be also considered just as a way 87 | // to adjust sensitivity factors of metrics 88 | assertThat(matcher.sequencesMatching("matha fey", "matshalaga obert"), is(false)); 89 | assertThat(matcher.sequencesMatching("tahir nasuf", "taghtiran pjs"), is(false)); 90 | assertThat(matcher.sequencesMatching("sal munz", "mupenzi bernard"), is(false)); 91 | assertThat(matcher.sequencesMatching("lochinvar farm", "farmacia la colina"), is(false)); 92 | } 93 | 94 | @Test 95 | public void shouldNotConsiderNonAlphanumericCharacters() { 96 | assertThat(matcher.sequencesMatching("t,e,r,r,o,r,i,s,t", "terrorist"), is(true)); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/java/com/ontheserverside/batch/bank/screening/SanctionScreeningProcessorTest.java: -------------------------------------------------------------------------------- 1 | package com.ontheserverside.batch.bank.screening; 2 | 3 | import com.ontheserverside.batch.bank.tx.Elixir0Transaction; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.springframework.test.util.ReflectionTestUtils; 7 | 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | import static org.easymock.EasyMock.createMock; 12 | import static org.easymock.EasyMock.expect; 13 | import static org.easymock.EasyMock.replay; 14 | import static org.easymock.EasyMock.verify; 15 | import static org.hamcrest.CoreMatchers.is; 16 | import static org.hamcrest.CoreMatchers.not; 17 | import static org.hamcrest.CoreMatchers.nullValue; 18 | import static org.junit.Assert.assertThat; 19 | 20 | public class SanctionScreeningProcessorTest { 21 | 22 | private static final String BENEFICIARY_NAME = "Brandon Beer"; 23 | private static final String ORDERING_PARTY_NAME = "Marcelle Rhee"; 24 | private static final String BENEFICIARY_ADDRESS_FULL = "Sienkiewicza 10 Kielce Poland"; 25 | private static final String ORDERING_PARTY_ADDRESS_FULL = "Meerschweinchen Platz 10 Berlin Germany"; 26 | 27 | private static final String SDN_ENTITY_NAME = "Daniele Hagen"; 28 | private static final String SDN_ENTITY_ALTERNATE_NAME = "Melanie Blundell"; 29 | private static final String SDN_ENTITY_ADDRESS = "Sunnyside 13C"; 30 | private static final String SDN_ENTITY_CITY = "New York"; 31 | private static final String SDN_ENTITY_COUNTRY = "USA"; 32 | private static final String SDN_ENTITY_ADDRESS_FULL = "Sunnyside 13C New York USA"; 33 | 34 | private FuzzyMatcher mockFuzzyMatcher; 35 | 36 | private SanctionScreeningProcessor processor; 37 | 38 | private SanctionScreeningContext context; 39 | 40 | @Before 41 | public void setUp() { 42 | this.mockFuzzyMatcher = createMock(FuzzyMatcher.class); 43 | this.processor = new SanctionScreeningProcessor(); 44 | ReflectionTestUtils.setField(processor, "fuzzyMatcher", mockFuzzyMatcher); 45 | 46 | Elixir0Transaction transaction = new Elixir0Transaction(); 47 | transaction.setBeneficiaryName(BENEFICIARY_NAME); 48 | transaction.setBeneficiaryAddress(BENEFICIARY_ADDRESS_FULL); 49 | transaction.setOrderingPartyName(ORDERING_PARTY_NAME); 50 | transaction.setOrderingPartyAddress(ORDERING_PARTY_ADDRESS_FULL); 51 | 52 | SDNEntity.SDNAddress sdnAddress = new SDNEntity.SDNAddress(SDN_ENTITY_ADDRESS, SDN_ENTITY_CITY, SDN_ENTITY_COUNTRY); 53 | List sdnAddresses = new LinkedList<>(); 54 | sdnAddresses.add(sdnAddress); 55 | 56 | List sdnAlternateNames = new LinkedList<>(); 57 | sdnAlternateNames.add(SDN_ENTITY_ALTERNATE_NAME); 58 | 59 | SDNEntity sdnEntity = new SDNEntity(SDN_ENTITY_NAME, sdnAddresses, sdnAlternateNames); 60 | 61 | this.context = new SanctionScreeningContext(transaction, sdnEntity); 62 | } 63 | 64 | @Test 65 | public void shouldMatchSanctionForBeneficaryName() { 66 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(true); 67 | replay(mockFuzzyMatcher); 68 | 69 | final SanctionMatch match = processor.process(context); 70 | 71 | verify(mockFuzzyMatcher); 72 | assertSanctionMatched(match); 73 | } 74 | 75 | @Test 76 | public void shouldMatchSanctionForOrderingPartyName() { 77 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 78 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(true); 79 | replay(mockFuzzyMatcher); 80 | 81 | final SanctionMatch match = processor.process(context); 82 | 83 | verify(mockFuzzyMatcher); 84 | assertSanctionMatched(match); 85 | } 86 | 87 | @Test 88 | public void shouldMatchSanctionForBeneficiaryAddress() { 89 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 90 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(false); 91 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(true); 92 | replay(mockFuzzyMatcher); 93 | 94 | final SanctionMatch match = processor.process(context); 95 | 96 | verify(mockFuzzyMatcher); 97 | assertSanctionMatched(match); 98 | } 99 | 100 | @Test 101 | public void shouldMatchSanctionForOrderingPartyAddress() { 102 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 103 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(false); 104 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 105 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(true); 106 | replay(mockFuzzyMatcher); 107 | 108 | final SanctionMatch match = processor.process(context); 109 | 110 | verify(mockFuzzyMatcher); 111 | assertSanctionMatched(match); 112 | } 113 | 114 | @Test 115 | public void shouldMatchSanctionForBeneficiaryAlternateName() { 116 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 117 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(false); 118 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 119 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 120 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_ALTERNATE_NAME)).andReturn(true); 121 | replay(mockFuzzyMatcher); 122 | 123 | final SanctionMatch match = processor.process(context); 124 | 125 | verify(mockFuzzyMatcher); 126 | assertSanctionMatched(match); 127 | } 128 | 129 | @Test 130 | public void shouldMatchSanctionForOrderingPartyAlternateName() { 131 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 132 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(false); 133 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 134 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 135 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_ALTERNATE_NAME)).andReturn(false); 136 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_ALTERNATE_NAME)).andReturn(true); 137 | replay(mockFuzzyMatcher); 138 | 139 | final SanctionMatch match = processor.process(context); 140 | 141 | verify(mockFuzzyMatcher); 142 | assertSanctionMatched(match); 143 | } 144 | 145 | @Test 146 | public void shouldNotWarnWhenSDNIsNotMatching() { 147 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_NAME)).andReturn(false); 148 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_NAME)).andReturn(false); 149 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 150 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_ADDRESS_FULL, SDN_ENTITY_ADDRESS_FULL)).andReturn(false); 151 | expect(mockFuzzyMatcher.sequencesMatching(BENEFICIARY_NAME, SDN_ENTITY_ALTERNATE_NAME)).andReturn(false); 152 | expect(mockFuzzyMatcher.sequencesMatching(ORDERING_PARTY_NAME, SDN_ENTITY_ALTERNATE_NAME)).andReturn(false); 153 | replay(mockFuzzyMatcher); 154 | 155 | final SanctionMatch match = processor.process(context); 156 | 157 | verify(mockFuzzyMatcher); 158 | assertThat(match, is(nullValue())); 159 | } 160 | 161 | private void assertSanctionMatched(final SanctionMatch match) { 162 | assertThat(match, is(not(nullValue()))); 163 | assertThat(match.getSdnEntity(), is(context.getSdnEntity())); 164 | assertThat(match.getTransaction(), is(context.getTransaction())); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /spring-batch-scalability/src/test/resources/elixir0/5Tx.elixir0: -------------------------------------------------------------------------------- 1 | 110,20140212,828749700184127,68578953,0,"87685789534046696210183491","81878754069967016032059101","SOUTHBOUND LTD.|8876 Harvest Leaf Harbour, Fighting Rock Corner, Maryland, 21069-9972, US","Vincenza Henkle|4489 Sunny Hickory Terrace, Enderby, Iowa, 50157-9431, US",0,87875406,"passkey deleaves rimmed sarsens sponsor",,,"51", 2 | 110,20140213,755630840255762,28853259,0,"23288532597190914003754934","91516297662112552760987574","Brandon Beer|6822 Amber Landing, The Black Cat, Kansas, 67889-2191, US","Bernardina Lockard|4608 Velvet Elk Boulevard, Gnaw Bone, District of Columbia, 20038-6201, US",0,51629766,"candida abasia millage",,,"51", 3 | 110,20140214,376940880227580,64619795,0,"69646197957014147272359008","50293167282244484554930786","Marcelle Rhee|3943 Pleasant Plaza, Uncle Sam, Arizona, 85565-6408, US","Nan Iliff|5784 Crystal Villas, Freeze, Michigan, 49662-9562, US",0,29316728,"outraged unfrocks choanae vividest pant",,,"51", 4 | 110,20140215,91114132441329,33161821,0,"20331618211296712712480029","2940308962994003559139606","Daniele Hagen|5257 Silent Range, Eighty Four, Oregon, 97408-9448, US","Myrna Schroth|4608 Velvet Elk Boulevard, Gnaw Bone, District of Columbia, 20038-6201, US",0,94030896,"mantlet",,,"51", 5 | 110,20140216,970869239262078,30035007,0,"2300350075447436145403143","12752321065837035161948168","Melani Blundell|5784 Crystal Villas, Freeze, Michigan, 49662-9562, US","SANTA CRUZ IMPERIAL AIRLINES|1709 Emerald Stead, Swisher, Yukon, Y0E-9S9, CA",0,75232106,"circlet lampoon hectare velocity",,,"51", --------------------------------------------------------------------------------