diff --git a/jdk_17_maven/cs/rest/digitalbanking/.gitignore b/jdk_17_maven/cs/rest/digitalbanking/.gitignore new file mode 100644 index 000000000..ab7355873 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/.gitignore @@ -0,0 +1,41 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### ds_store +**/.DS_Store + +### docker directories +/cassandra/cassandra +/cassandra/redis_data/ +/redis_data diff --git a/jdk_17_maven/cs/rest/digitalbanking/README.md b/jdk_17_maven/cs/rest/digitalbanking/README.md new file mode 100644 index 000000000..2366922c0 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/README.md @@ -0,0 +1,198 @@ +# Redisearch-Digital-Banking-redistemplate + +Provides a quick-start example of using Redis with springBoot with Banking structures. Digital Banking uses an API microservices approach to enable high speed requests for account, customer and transaction information. As seen below, this data is useful for a variety of business purposes in the bank. + + +### Note: This is the same as Redisearch-Digital-Banking but uses redistemplate instead of any of the crudrepository indexes. redisearch 2.0 indexes will be used. This is not using the crudrepository for the basic redis data. + +## Overview +In this tutorial, a java spring boot application is run through a jar file to support typical API calls to a REDIS banking data layer. A redis docker configuration is included. + +## Redis Advantages for Digital Banking + * Redis easily handles high write transaction volume + * Redis has no tombstone issues and can upsert posted transactions over pending + * Redis Enterprise scales vertically (large nodes) and horizontally (many nodes) + * Redisearch 2.0 automatically indexes the hash structure created by Spring Java CRUD repository + +## Requirements +* Docker installed on your local system, see [Docker Installation Instructions](https://docs.docker.com/engine/installation/). +* Alternatively, can run Redis Enterprise and set the redis host and port in the application.properties file +* When using Docker for Mac or Docker for Windows, the default resources allocated to the linux VM running docker are 2GB RAM and 2 CPU's. Make sure to adjust these resources to meet the resource requirements for the containers you will be running. More information can be found here on adjusting the resources allocated to docker. + +[Docker for mac](https://docs.docker.com/docker-for-mac/#advanced) +[Docker for windows](https://docs.docker.com/docker-for-windows/#advanced) + +## Links that help! + + * [Redis Stack](https://redis.com/blog/introducing-redis-stack/) + * [Redis Search](https://redis.io/docs/stack/search/) + * [Redis Insight](https://redis.io/docs/stack/insight/) + * [Spring Data for Redis github](https://github.com/spring-projects/spring-data-examples/tree/master/redis/repositories) + * [Spring Data for Cassandra](https://www.baeldung.com/spring-data-cassandra-tutorial) + * [Spring Data for Kafka](https://www.baeldung.com/spring-kafka) + * [spring data Reference in domain](https://github.com/spring-projects/spring-data-examples/blob/master/redis/repositories/src/main/java/example/springdata/redis/repositories/Person.java) + * [spring async tips](https://dzone.com/articles/effective-advice-on-spring-async-part-1) + * [swagger-ui with spring](https://www.baeldung.com/spring-rest-openapi-documentation) + * + + +## Technical Overview + +This github java code uses jedis library for redis. The jedis library supports RediSearch, RedisJSON, and RedisTimeSeries. The original github only used spring java without redisearch. That repository is still intact at [this github location](https://github.com/jphaugla/Redis-Digital-Banking). Another subsequent version uses crud repository and search at [this github location](https://github.com/jphaugla/Redisearch-Digital-Banking) +All of the Spring Java indexes have been removed in this version. The crud repository has been removed. +### The spring java code +This is basic spring links +* [Spring Redis](https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis.repositories.indexes) +* *boot*-Contains index creation for each of the four redisearch indexes used in this solution: Account, Customer, Merchant, and Transaction +* *config*-Initial configuration module using autoconfiguration and a threadpool sizing to adjust based on machine size +* *controller*-http API call interfaces +* *data*-code to generate POC type of customer, account, and transaction code +* *domain*-has each of the java objects with their columns. Enables all the getter/setter methods +* *repository*-has repository definitions. With transition to redisearch 2.0, not used as heavily as previously. This is where the redistemplate code is added if crud repository is no longer used. Cassandra transaction repository is also here. +* *service*-asyncservice, topicproducer (kafka) and bankservice doing the interaction with redis +### +The java code demonstrates common API actions with the data layer in REDIS. The java spring Boot framework minimizes the amount of code to build and maintain this solution. Maven is used to build the java code and the code is deployed to the tomcat server. + +### Data Structures in use + + +## Using Docker for non-application components +This option uses docker to support all of the non-application components (kafka, cassandra, redis) with the java application running on the local mac. +* Prepare Docker environment-see the Prerequisites section above... +* Pull this github into a directory +```bash +git clone https://github.com/jphaugla/Redisearch-Digital-Banking.git +``` +* Refer to the notes for redis Docker images used but don't get too bogged down as docker compose handles everything except for a few admin steps on tomcat. + * [Redis stack docker instructions](https://redis.io/docs/stack/get-started/install/docker/) +* Open terminal and change to the github home where you will see the docker-compose.yml file, then: +```bash +docker-compose -f docker-compose-kafka.yml -f docker-compose.yml -f docker-compose-cassandra.yml up -d +``` +## Deploying java application on local mac with Kafka non-application components +* ensure maven and java are deployed on the local machine + * have been running with java 17 or java 18 but other versions should work as well + * have been runing with 3.9.4 and 3.9.5 +* Set up the environment and run the java application locally + * edit the [environment file](scripts/setEnv.sh) to use localhost for non-application components + * source this environment file + * run the application +```bash +source scripts/setEnv.sh +java -jar target/redis-0.0.1-SNAPSHOT.jar +``` + +## Using terraform on azure for all components + +* Use [this github](https://github.com/jphaugla/tfmodule-azure-redis-enterprise) to deploy all of the components (including the application) +* Check the [readme](https://github.com/jphaugla/tfmodule-azure-redis-enterprise/README.md) for the details on deploying this github including the cloning the github and working with Azure. Completely deploy the terraform github for all deployments. This will also deploy [this github](https://github.com/jphaugla/Redisearch-Digital-Banking-redisTemplate) inside the tester node. The later application deployment instructions will be deployed within the tester node using ssh +* maven and java will be installed by the ansible jobs for the tester node +* the ip and dns information is shared in a [temp directory](https://github.com/jphaugla/tfmodule-azure-redis-enterprise/provisioners/temp) within the terraform/ansible repository. Go to the files here to see private (internal) and public (external) kafka node, cassandra node and testinnode IP addresses. The redis internal and external database connection dns names are also available. These dns names will also give an internal and external redis enterprise node IP. +* log into the tester node using the testernode IP and the ssh key defined in test/main.tf and go to github home +```bash +ssh -i redislabs@ +cd Redisearch-Digital-Banking-redisTemplate +``` +* edit the [environment file](scripts/setEnv.sh) using only the internal connection addresses. NOTE: kafka will only connect from local azure IP addresses and not any public IP addresses. Using public and private Kafka addresses is possible but not configured currently +* These steps can all be done from client machine local browser using the kafka node public IP address and port 9021. [http://172.172.133.201:9021/](http://172.172.133.201:9021/) From this home screen, pause the currently running connectors: datagen-pageviews, cassanddra-sink, and redis-sink-json using the Kafka Control Center. This will just remove the noise of a second application running. +* Consider cleaning both the redis (use flushdb) and cassandra databases as well (drop keyspace pageviews) +* Create transaction table in cassandra using provided script +```bash +cd scripts +# edit the CQLSH_HOST variable inside the script for the cassandra host pubic IP address +./createCassandraTrans.sh +``` +* start the application after logging in to the testernode +```bash +ssh -i ~/.ssh/ redislabs@ +cd Redisearch-Digital-Banking-redisTemplate +mvn clean package +# edit scripts/setEnv.sh for current nodes - REDIS_HOST, REDIS_PORT, and KAFKA_HOST must all change to match current environment. *IMPORTANT* only use private/internal IP addresses-DO NOT USE *localhost*. Additional note, redis password is different in local docker version and in ansible created version-verify redis password! +source scripts/setEnv.sh +java -jar target/redis-0.0.1-SNAPSHOT.jar +``` +* get a second terminal window to the tester node and write a test message to kafka-this will cause the topic to be created. Name can be changed in [application.properties](src/main/resources/application.properites) but default topic name is *transactions* +```bash +ssh -i ~/.ssh/ redislabs@ +cd Redisearch-Digital-Banking-redisTemplate/scripts +# make sure saveTransaction script says doKafka=true +./saveTransaction.sh +``` +* verify transactions topic is created using kafka control center + * in control center click on topics and then on the topics page, click messages + * if you run saveTransaction.sh again while looking at the control center topic pane, the message will be visible. If you put offset of 0, both messages will be visible. + * application will create the kafka topic on first usage of the topic. +* Call kafka API to create the RedisSink using provided script. DO THIS FROM your local Mac +```bash +cd Redisearch-Digital-Banking-redisTemplate/scripts +# change localhost to the external/public ip address for the kafka node in the last line. +# Make sure this is the public kafka IP and not the private +# Verify the redis.uri and redis.password. (the redis.uri must be INTERNAL) +./createRedisSink.sh +ssh -i ~/.ssh/ redislabs@ +./saveTransaction.sh +``` +verify data flowed in to redis using redis-cli +```bash +redis-cli -h -p -a redis123 +>keys Trans* + + +* Call an Api to create the cassandra sink using provided script +```bash +# on local mac +cd Redisearch-Digital-Banking-redisTemplate/scripts +# change localhost to the public ip address for the kafka node in the last line. +# Set the contactPoints to the local IP address for the cassandra node. +./createCassandraSink.sh +ssh -i ~/.ssh/ redislabs@ +./saveTransaction.sh +``` +verify data flowed in to cassandra using cqlsh + +## process larger record set +verify generateData.sh says doKafkfa=true +```bash +./scripts/generateData.sh +``` +Will see large number of records now in cassandra and redis + +Shows a benchmark test run of generateData.sh on GCP servers. Although, this test run is using redisearch 1.0 code base. Need to rerun this test. + + +### Investigate the APIs +#### Use swagger UI +* [open api docs](http://localhost:8080/v3/api-docs) +* [use swagger ui](http://localhost:8080/swagger-ui/index.html) +#### run bash scripts in ./scripts. Adding the redisearch queries behind each script here also... + * addTag.sh - add a tag to a transaction. Tags allow user to mark transactions to be in a buckets such as Travel or Food for budgetary tracking purposes + * deleteCustomer.sh - delete all customers matching a string + * generateData.sh - simple API to generate default customer, accounts, merchants, phone numbers, emails and transactions + * generateLots.sh - for server testing to generate higher load levels. Use with startAppservers.sh. Not for use with docker setup. This is load testing with redis enterprise and client application running in same network in the cloud. + * getByAccount.sh - find transactions for an account between a date range + * getByCreditCard.sh - find transactions for a credit card between a date range + * getByCustID.sh - retrieve transactions for customer + * getByEmail.sh - retrieve customer record using email address + * getByMerchant.sh - find all transactions for an account from one merchant for date range + * getByMerchantCategory.sh - find all transactions for an account from merchant category for date range + * getByNamePhone.sh - get customers by phone and full name. + * getByPhone.sh - get customers by phone only + * getByStateCity.sh - get customers by city and state + * getByZipLastname.sh - get customers by zipcode and lastname. + * getReturns.sh - get returned transactions count by reason code + * getTags.sh - get all tags on an account + * getTaggedAccountTransactions.sh - find transactions for an account with a particular tag + * getTransaction.sh - get one transaction by its transaction ID + * getTransactionStatus.sh - see count of transactions by account status of PENDING, AUTHORIZED, SETTLED + * putCustomer.sh - put a set of json customer records + * saveAccount.sh - save a sample account + * saveCustomer.sh - save a sample customer + * saveTransaction.sh - save a sample Transaction + * startAppservers.sh - start multiple app server instances for load testing + * testPipeline.sh - test pipelining + * updateTransactionStatus.sh - generate new transactions to move all transactions from one transaction Status up to the next transaction status. Parameter is target status. Can choose SETTLED or POSTED. Will move 100,000 transactions per call + * putDispute.sh - put the dispute specified in dispute.sh + * disputeReasonCode.sh - set the dispute reason code + * disputeAccept.sh - accept the dispute + * disputeResolved.sh - charge back the dispute + diff --git a/jdk_17_maven/cs/rest/digitalbanking/docker-compose-cassandra.yml b/jdk_17_maven/cs/rest/digitalbanking/docker-compose-cassandra.yml new file mode 100644 index 000000000..cf39a4b1d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/docker-compose-cassandra.yml @@ -0,0 +1,25 @@ +version: '3.9' + +services: + + cassandra1: + image: 'cassandra:latest' + environment: + - CASSANDRA_CLUSTER_NAME=test + - CASSANDRA_SEEDS=cassandra1 +# this is actually hardcoded with SIMPLE Snitch + - CASSANDRA_DC=datacenter1 + - CASSANDRA_ENDPOINT_SNITCH=SimpleSnitch + - CASSANDRA_BROADCAST_ADDRESS=cassandra1 + container_name: cassandra1 + hostname: cassandra1 + ports: + - '9042:9042' + - '9160:9160' + + cassandra-load-keyspace: + container_name: cassandra-load-keyspace + image: 'cassandra:latest' + volumes: + - ./cassandra_init:/cassandra_init/ + entrypoint: [ "bash", "/cassandra_init/init.sh" ] diff --git a/jdk_17_maven/cs/rest/digitalbanking/docker-compose-kafka.yml b/jdk_17_maven/cs/rest/digitalbanking/docker-compose-kafka.yml new file mode 100644 index 000000000..d302c857d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/docker-compose-kafka.yml @@ -0,0 +1,147 @@ +--- +version: '2' +services: + zookeeper: + image: confluentinc/cp-zookeeper:7.2.0 + hostname: zookeeper + container_name: zookeeper + ports: + - "2181:2181" + environment: + ZOOKEEPER_CLIENT_PORT: 2181 + ZOOKEEPER_TICK_TIME: 2000 + + broker: + image: confluentinc/cp-server:7.2.0 + hostname: broker + container_name: broker + depends_on: + - zookeeper + ports: + - "9092:9092" + - "9101:9101" + environment: + KAFKA_BROKER_ID: 1 + KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092 + KAFKA_METRIC_REPORTERS: io.confluent.metrics.reporter.ConfluentMetricsReporter + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 + KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 + KAFKA_JMX_PORT: 9101 + KAFKA_JMX_HOSTNAME: localhost + KAFKA_CONFLUENT_SCHEMA_REGISTRY_URL: http://schema-registry:8081 + CONFLUENT_METRICS_REPORTER_BOOTSTRAP_SERVERS: broker:29092 + CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS: 1 + CONFLUENT_METRICS_ENABLE: 'true' + CONFLUENT_SUPPORT_CUSTOMER_ID: 'anonymous' + + schema-registry: + image: confluentinc/cp-schema-registry:7.2.0 + hostname: schema-registry + container_name: schema-registry + depends_on: + - broker + ports: + - "8081:8081" + environment: + SCHEMA_REGISTRY_HOST_NAME: schema-registry + SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: 'broker:29092' + SCHEMA_REGISTRY_LISTENERS: http://0.0.0.0:8081 + + connect: + image: fieldengineering/redis-kafka-connect + hostname: connect + container_name: connect + depends_on: + - broker + - schema-registry + ports: + - "8083:8083" + volumes: + - ./confluent-hub-components:/usr/share/confluent-hub-components/ + environment: + CONNECT_BOOTSTRAP_SERVERS: 'broker:29092' + CONNECT_REST_ADVERTISED_HOST_NAME: connect + CONNECT_GROUP_ID: compose-connect-group + CONNECT_CONFIG_STORAGE_TOPIC: docker-connect-configs + CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: 1 + CONNECT_OFFSET_FLUSH_INTERVAL_MS: 10000 + CONNECT_OFFSET_STORAGE_TOPIC: docker-connect-offsets + CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: 1 + CONNECT_STATUS_STORAGE_TOPIC: docker-connect-status + CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: 1 + CONNECT_KEY_CONVERTER: org.apache.kafka.connect.storage.StringConverter + CONNECT_VALUE_CONVERTER: io.confluent.connect.avro.AvroConverter + CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL: http://schema-registry:8081 + # CLASSPATH required due to CC-2422 + CLASSPATH: /usr/share/java/monitoring-interceptors/monitoring-interceptors-7.2.0.jar + CONNECT_PRODUCER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor" + CONNECT_CONSUMER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor" + CONNECT_PLUGIN_PATH: "/usr/share/java,/usr/share/confluent-hub-components" + CONNECT_LOG4J_LOGGERS: org.apache.zookeeper=ERROR,org.I0Itec.zkclient=ERROR,org.reflections=ERROR + + control-center: + image: confluentinc/cp-enterprise-control-center:7.2.0 + hostname: control-center + container_name: control-center + depends_on: + - broker + - schema-registry + - connect + - ksqldb-server + ports: + - "9021:9021" + environment: + CONTROL_CENTER_BOOTSTRAP_SERVERS: 'broker:29092' + CONTROL_CENTER_CONNECT_CONNECT-DEFAULT_CLUSTER: 'connect:8083' + CONTROL_CENTER_KSQL_KSQLDB1_URL: "http://ksqldb-server:8088" + CONTROL_CENTER_KSQL_KSQLDB1_ADVERTISED_URL: "http://localhost:8088" + CONTROL_CENTER_SCHEMA_REGISTRY_URL: "http://schema-registry:8081" + CONTROL_CENTER_REPLICATION_FACTOR: 1 + CONTROL_CENTER_INTERNAL_TOPICS_PARTITIONS: 1 + CONTROL_CENTER_MONITORING_INTERCEPTOR_TOPIC_PARTITIONS: 1 + CONFLUENT_METRICS_TOPIC_REPLICATION: 1 + PORT: 9021 + + ksqldb-server: + image: confluentinc/cp-ksqldb-server:7.2.0 + hostname: ksqldb-server + container_name: ksqldb-server + depends_on: + - broker + - connect + ports: + - "8088:8088" + environment: + KSQL_CONFIG_DIR: "/etc/ksql" + KSQL_BOOTSTRAP_SERVERS: "broker:29092" + KSQL_HOST_NAME: ksqldb-server + KSQL_LISTENERS: "http://0.0.0.0:8088" + KSQL_CACHE_MAX_BYTES_BUFFERING: 0 + KSQL_KSQL_SCHEMA_REGISTRY_URL: "http://schema-registry:8081" + KSQL_PRODUCER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor" + KSQL_CONSUMER_INTERCEPTOR_CLASSES: "io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor" + KSQL_KSQL_CONNECT_URL: "http://connect:8083" + KSQL_KSQL_LOGGING_PROCESSING_TOPIC_REPLICATION_FACTOR: 1 + KSQL_KSQL_LOGGING_PROCESSING_TOPIC_AUTO_CREATE: 'true' + KSQL_KSQL_LOGGING_PROCESSING_STREAM_AUTO_CREATE: 'true' + + rest-proxy: + image: confluentinc/cp-kafka-rest:7.2.0 + depends_on: + - broker + - schema-registry + ports: + - 8082:8082 + hostname: rest-proxy + container_name: rest-proxy + environment: + KAFKA_REST_HOST_NAME: rest-proxy + KAFKA_REST_BOOTSTRAP_SERVERS: 'broker:29092' + KAFKA_REST_LISTENERS: "http://0.0.0.0:8082" + KAFKA_REST_SCHEMA_REGISTRY_URL: 'http://schema-registry:8081' diff --git a/jdk_17_maven/cs/rest/digitalbanking/docker-compose.yml b/jdk_17_maven/cs/rest/digitalbanking/docker-compose.yml new file mode 100644 index 000000000..9618dcd5d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.9' +services: + + redis: + image: redis/redis-stack:latest + container_name: redis + hostname: redis + environment: + REDIS_ARGS: "--requirepass jasonrocks" + ports: + - "6379:6379" + - "8001:8001" + volumes: + - ./redis_data:/data + diff --git a/jdk_17_maven/cs/rest/digitalbanking/images/Benchmark.png b/jdk_17_maven/cs/rest/digitalbanking/images/Benchmark.png new file mode 100644 index 000000000..21080b65a Binary files /dev/null and b/jdk_17_maven/cs/rest/digitalbanking/images/Benchmark.png differ diff --git a/jdk_17_maven/cs/rest/digitalbanking/images/DigitalBanking.png b/jdk_17_maven/cs/rest/digitalbanking/images/DigitalBanking.png new file mode 100644 index 000000000..b43e05303 Binary files /dev/null and b/jdk_17_maven/cs/rest/digitalbanking/images/DigitalBanking.png differ diff --git a/jdk_17_maven/cs/rest/digitalbanking/images/Springindexes.png b/jdk_17_maven/cs/rest/digitalbanking/images/Springindexes.png new file mode 100644 index 000000000..ce9f89bed Binary files /dev/null and b/jdk_17_maven/cs/rest/digitalbanking/images/Springindexes.png differ diff --git a/jdk_17_maven/cs/rest/digitalbanking/images/Tables.png b/jdk_17_maven/cs/rest/digitalbanking/images/Tables.png new file mode 100644 index 000000000..4f85592f9 Binary files /dev/null and b/jdk_17_maven/cs/rest/digitalbanking/images/Tables.png differ diff --git a/jdk_17_maven/cs/rest/digitalbanking/images/deployment.png b/jdk_17_maven/cs/rest/digitalbanking/images/deployment.png new file mode 100644 index 000000000..a4d9028ca Binary files /dev/null and b/jdk_17_maven/cs/rest/digitalbanking/images/deployment.png differ diff --git a/jdk_17_maven/cs/rest/digitalbanking/pom.xml b/jdk_17_maven/cs/rest/digitalbanking/pom.xml new file mode 100644 index 000000000..22e523324 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/pom.xml @@ -0,0 +1,122 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + com.jphaugla + redis + 0.0.1-SNAPSHOT + redis + Demo project for Spring Boot with Redis + jar + + + com.jphaugla.DemoApplication + 4.4.3 + 4.17.0 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + redis.clients + jedis + ${version.jedis} + + + org.apache.commons + commons-pool2 + + + org.springframework.boot + spring-boot-starter-data-rest + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + 1.18.30 + provided + + + joda-time + joda-time + 2.12.5 + + + org.apache.kafka + kafka-streams + + + org.springframework.boot + spring-boot-starter-data-cassandra + + + org.springframework.kafka + spring-kafka + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.2.0 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + + diff --git a/jdk_17_maven/cs/rest/digitalbanking/runJob.sh b/jdk_17_maven/cs/rest/digitalbanking/runJob.sh new file mode 100644 index 000000000..48dd1d5c7 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/runJob.sh @@ -0,0 +1 @@ +java -Djavax.net.debug=ssl -Djavax.net.ssl.keyStore=src/main/resources/ssl/client-keystore.p12 -Djavax.net.ssl.keyStorePassword=${KEYSTORE_PASSWORD} -Djavax.net.ssl.trustStore=src/main/resources/ssl/client-truststore.p12 -Djavax.net.ssl.trustStorePassword=${TRUSTSTORE_PASSWORD} -jar target/redis-0.0.1-SNAPSHOT.jar diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag.sh new file mode 100644 index 000000000..2b5318247 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag.sh @@ -0,0 +1,3 @@ +# add a tag to a transaction. Tags allow user to mark transactions to be in a buckets such as Travel or Food for budgetary tracking purposes +# date can be looked up and put in range +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/addTag?transactionID=379369J&tag=Travel&operation=ADD' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag2.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag2.sh new file mode 100644 index 000000000..71aad435c --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/addTag2.sh @@ -0,0 +1,3 @@ +# add a tag to a transaction. Tags allow user to mark transactions to be in a buckets such as Travel or Food for budgetary tracking purposes +# date can be looked up and put in range +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/addTag?transactionID=4484J&tag=Food&operation=ADD' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraSink.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraSink.sh new file mode 100644 index 000000000..6c96b75da --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraSink.sh @@ -0,0 +1,18 @@ +curl -X POST -H "Content-Type: application/json" --data ' +{ + "name": "cassandra-sink-trans", + "config": { + "topic.transactions.banking.transaction.mapping": "tranid=value.tranid, accountno=value.accountno, amounttype=value.amounttype, merchant=value.merchant, referencekeytype=value.referencekeytype, referencekeyvalue=value.referencekeyvalue, originalamount=value.originalamount, amount=value.amount, trancd=value.trancd, description=value.description, initialdate=value.initialdate, settlementdate=value.settlementdate, postingdate=value.postingdate, status=value.status, location=value.location", + "key.converter.schemas.enable": "false", + "value.converter.schemas.enable": "false", + "name": "cassandra-sink-trans", + "connector.class": "com.datastax.kafkaconnector.DseSinkConnector", + "tasks.max": "1", + "key.converter": "org.apache.kafka.connect.storage.StringConverter", + "value.converter": "org.apache.kafka.connect.json.JsonConverter", + "topics": "transactions", + "contactPoints": "10.0.11.7", + "loadBalancing.localDc": "datacenter1" + } +} +} ' http://172.191.110.145:8083/connectors -w "\n" diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraTrans.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraTrans.sh new file mode 100644 index 000000000..b43fca83c --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/createCassandraTrans.sh @@ -0,0 +1,3 @@ +export CQLSH_HOST=4.236.143.55 +cqlsh -e "create keyspace if not exists banking with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 } ;" +cqlsh < trans.cql diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/createRedisSink.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/createRedisSink.sh new file mode 100644 index 000000000..450de22e6 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/createRedisSink.sh @@ -0,0 +1,22 @@ +curl -X POST -H "Content-Type: application/json" --data ' +{ + "name": "redis-sink-trans", + "config": { + "value.converter.schemas.enable": "false", + "name": "redis-sink-trans", + "connector.class": "com.redis.kafka.connect.RedisSinkConnector", + "tasks.max": "1", + "key.converter": "org.apache.kafka.connect.storage.StringConverter", + "value.converter": "org.apache.kafka.connect.json.JsonConverter", + "transforms": "Cast", + "topics": "transactions", + "transforms.Cast.type": "org.apache.kafka.connect.transforms.Cast$Key", + "transforms.Cast.spec": "string", + "redis.uri": "redis://redis-19716.int.jph.jphaugla.demo-rlec.redislabs.com:19716", + "redis.password": "redis123", + "redis.type": "HASH", + "redis.key": "Trans", + "redis.separator": ":" + } +} +} ' http://172.191.110.145:8083/connectors -w "\n" diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer.json new file mode 100644 index 000000000..dd78cb80d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer.json @@ -0,0 +1 @@ +{ "customerId": "cust001", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Bruno", "fullName":"Bruno Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer1.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer1.json new file mode 100644 index 000000000..bf12db900 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer1.json @@ -0,0 +1 @@ +{ "customerId": "cust005", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Jorge", "fullName":"Jorge Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer2.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer2.json new file mode 100644 index 000000000..1df7a587a --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer2.json @@ -0,0 +1 @@ +{ "customerId": "cust004", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Edward", "fullName":"Edward Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer3.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer3.json new file mode 100644 index 000000000..cb5aaf482 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer3.json @@ -0,0 +1 @@ +{ "customerId": "cust002", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Susan", "fullName":"Susan Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer4.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer4.json new file mode 100644 index 000000000..87a18635d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer4.json @@ -0,0 +1 @@ +{ "customerId": "cust003", "addressLine1": "4745 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"George", "fullName":"George Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer5.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer5.json new file mode 100644 index 000000000..ef346f925 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer5.json @@ -0,0 +1 @@ +{ "customerId": "cust006", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Robert", "fullName":"Robert Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/customer6.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer6.json new file mode 100644 index 000000000..8cc0f6c81 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/customer6.json @@ -0,0 +1 @@ +{ "customerId": "cust007", "addressLine1": "4744 17th av s", "addressLine2": "", "addressType": "home", "billPayEnrolled": "", "city": "Minneapolis", "countryCode":"00", "createdBy":"jph", "customerOriginSystem":"IDR", "customerStatus":"A", "customerType":"BANK", "dateOfBirth":"1949.01.23", "firstName":"Oliver", "fullName":"Oliver Waldo Emerson", "gender":"M", "governmentId":"8887778989", "governmentIdType":"SSN", "lastName":"Emerson", "lastUpdatedBy":"jph", "middleName":"Waldo", "prefix":"MR", "queryHelperColumn":"help", "stateAbbreviation":"MN", "zipcode":"55444", "zipcode4":"55444-3322" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomerEmail.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomerEmail.sh new file mode 100644 index 000000000..8675cf3f0 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomerEmail.sh @@ -0,0 +1,3 @@ +# retrieve transations for customer +# get using a customer id. Use redisinsight's search to find a good custid +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/deleteCustomerEmail?customerId=cust006' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomers.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomers.sh new file mode 100644 index 000000000..ffd098435 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/deleteCustomers.sh @@ -0,0 +1,3 @@ +# retrieve transations for customer +# get using a customer id. Use redisinsight's search to find a good custid +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/deleteCustomer?customerString=cust0*' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/dispute.json b/jdk_17_maven/cs/rest/digitalbanking/scripts/dispute.json new file mode 100644 index 000000000..cb58d0e11 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/dispute.json @@ -0,0 +1 @@ +{ "disputeId": "668123", "tranId": "1234", "filingDate": "2023/07/27", "status": "Initiated" } diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeAccept.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeAccept.sh new file mode 100644 index 000000000..d367d04c6 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeAccept.sh @@ -0,0 +1 @@ +curl -X PUT -H "Content-Type: application/json" 'http://localhost:8080/acceptDispute?disputeId=668123' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeReasonCode.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeReasonCode.sh new file mode 100644 index 000000000..a50fe3800 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeReasonCode.sh @@ -0,0 +1 @@ +curl -X PUT -H "Content-Type: application/json" 'http://localhost:8080/putDisputeChargeBackReason?disputeId=668123&reasonCode=11.1' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeResolved.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeResolved.sh new file mode 100644 index 000000000..31d92439c --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/disputeResolved.sh @@ -0,0 +1 @@ +curl -X PUT -H "Content-Type: application/json" 'http://localhost:8080/resolvedDispute?disputeId=668123' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/generateData.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/generateData.sh new file mode 100644 index 000000000..5cf80e46a --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/generateData.sh @@ -0,0 +1,7 @@ +# This script uses an API call to generate sample banking customers, +# accounts and transactions. It uses Spring ASYNC techniques to +# generate higher load. A flag chooses between running the transactions +# pipelined in Redis or in normal non-pipelined method. +curl 'http://localhost:8080/generateData?noOfCustomers=500&noOfTransactions=100000&noOfDays=5&key_suffix=J&doKafka=true' +# with ssl +# curl -cacert='..//src/main/resources/ssl/proxy-cert.pem' 'http://localhost:8080/generateData?noOfCustomers=500&noOfTransactions=100000&noOfDays=5&key_suffix=J' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/generateLots.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/generateLots.sh new file mode 100644 index 000000000..af3676a14 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/generateLots.sh @@ -0,0 +1,8 @@ +# for server testing to generate higher load levels. +# Use with startAppservers.sh +nohup curl 'http://localhost:8080/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=J' > /tmp/generateJ.out 2>&1 & +nohup curl 'http://localhost:8081/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=P' > /tmp/generateP.out 2>&1 & +nohup curl 'http://localhost:8082/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=H' > /tmp/generateH.out 2>&1 & +nohup curl 'http://localhost:8083/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=C' > /tmp/generateC.out 2>&1 & +nohup curl 'http://localhost:8084/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=A' > /tmp/generateA.out 2>&1 & +nohup curl 'http://localhost:8085/generateData?noOfCustomers=5000&noOfTransactions=100000&noOfDays=10&key_suffix=G' > /tmp/generateG.out 2>&1 & diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByAccount.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByAccount.sh new file mode 100644 index 000000000..abe9d0406 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByAccount.sh @@ -0,0 +1,3 @@ +# easiest to look up an account using redinsight and edit this script to find an existing account +# date can be looked up and put in range +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/accountTransactions?accountNo=Acct1076J&from=2023-07-21&to=2023-11-21' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCreditCard.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCreditCard.sh new file mode 100644 index 000000000..167a35c5f --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCreditCard.sh @@ -0,0 +1,3 @@ +# easiest to look up a credit card using redinsight and edit this script to find an existing credit card +# date can be looked up and put in range +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/creditCardTransactions?creditCard=9a3b56b5x5227x459fxa67dx36e157c400f7&account=Acct1076J&from=2023-07-27&to=2023-11-30' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCustID.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCustID.sh new file mode 100644 index 000000000..69b793401 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByCustID.sh @@ -0,0 +1,3 @@ +# retrieve transations for customer +# get using a customer id. Use redisinsight's search to find a good custid +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customer?customerId=cust0001' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByEmail.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByEmail.sh new file mode 100644 index 000000000..3ca7ebb15 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByEmail.sh @@ -0,0 +1,3 @@ +# retrieve customer record using email address +# get by email only +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customerByEmail?email=1000013J@gmail.com' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchant.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchant.sh new file mode 100644 index 000000000..118a233d2 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchant.sh @@ -0,0 +1,3 @@ +# find all transactions for an account from one merchant in date range +# easiest to look up in Redisinsight and plug value +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/merchantTransactions?merchant=Walmart&account=Acct195J&from=2022-06-27&to=2023-11-23' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchantCategory.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchantCategory.sh new file mode 100644 index 000000000..a98dead1e --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByMerchantCategory.sh @@ -0,0 +1,2 @@ +# find all transactions for an account from merchant category for date range +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/merchantCategoryTransactions?merchantCategory=5732&account=Acct450J&from=2022-07-27&to=2023-10-30' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByNamePhone.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByNamePhone.sh new file mode 100644 index 000000000..354170591 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByNamePhone.sh @@ -0,0 +1,2 @@ +# get by phone and full name. Notice the ascii string for the space +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customerByPhone?phoneString=1000088Jw&full_name=Igor%20Golov%2000088' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByPhone.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByPhone.sh new file mode 100644 index 000000000..23d013f6f --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByPhone.sh @@ -0,0 +1,2 @@ +# get customers by phone only +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customerByPhone?phoneString=1000085Jh' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByStateCity.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByStateCity.sh new file mode 100644 index 000000000..28e4447a3 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByStateCity.sh @@ -0,0 +1,2 @@ +# get customers by city and state +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customerByStateCity?state=IL&city=Chicago' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getByZipLastname.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByZipLastname.sh new file mode 100644 index 000000000..30232a175 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getByZipLastname.sh @@ -0,0 +1,2 @@ +# get by zipcode and lastname. Lastname is a generated integer +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/customerByZipcodeLastname?zipcode=55435&lastname=00097' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getReturns.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getReturns.sh new file mode 100644 index 000000000..fd2c64165 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getReturns.sh @@ -0,0 +1,3 @@ +# get all returned transactions +# +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/returned_transactions' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getTaggedAccountTransactions.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTaggedAccountTransactions.sh new file mode 100644 index 000000000..b17cd2964 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTaggedAccountTransactions.sh @@ -0,0 +1,3 @@ +# get all tags on an account +# +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/getTaggedTransactions?accountNo=Acct1179J&tag=Travel' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransaction.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransaction.sh new file mode 100644 index 000000000..a7b7e89a6 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransaction.sh @@ -0,0 +1,2 @@ +# get one transaction by ID +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/getTransaction?transactionID=45115J' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionStatus.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionStatus.sh new file mode 100644 index 000000000..c431ebff2 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionStatus.sh @@ -0,0 +1,3 @@ +# see count of transactions by account status of PENDING, AUTHORIZED, SETTLED +# not working +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/transactionStatusReport' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionTags.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionTags.sh new file mode 100644 index 000000000..7f3ef6ccc --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/getTransactionTags.sh @@ -0,0 +1,3 @@ +# get all tags on an account +# +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/getTags?transactionID=379369J' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/putCustomer.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/putCustomer.sh new file mode 100644 index 000000000..de2cc4ce4 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/putCustomer.sh @@ -0,0 +1,7 @@ +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer1.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer2.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer3.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer4.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer5.json +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postCustomer?customer --data @customer6.json diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/putDispute.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/putDispute.sh new file mode 100644 index 000000000..4aac0ce77 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/putDispute.sh @@ -0,0 +1 @@ +curl -X POST -H "Content-Type: application/json" http://localhost:8080/postDispute?dispute --data @dispute.json diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/saveAccount.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveAccount.sh new file mode 100644 index 000000000..706a95815 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveAccount.sh @@ -0,0 +1,2 @@ +# save a sample account +curl http://localhost:8080/save_account diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/saveCustomer.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveCustomer.sh new file mode 100644 index 000000000..d4ebf8c49 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveCustomer.sh @@ -0,0 +1,2 @@ +# save a sample customer +curl http://localhost:8080/save_customer diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/saveTransaction.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveTransaction.sh new file mode 100644 index 000000000..6280fb341 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/saveTransaction.sh @@ -0,0 +1,2 @@ +# save a sample transaction +curl http://localhost:8080/save_transaction?doKafka=true diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/search.txt b/jdk_17_maven/cs/rest/digitalbanking/scripts/search.txt new file mode 100644 index 000000000..976341297 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/search.txt @@ -0,0 +1,2 @@ +ft.search Customer "@stateAbbreviation:MN @city:Edina" +ft.search Customer "@stateAbbreviation:MN @city:Edina" return 2 fullName customerId diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/setEnv.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/setEnv.sh new file mode 100644 index 000000000..c29567321 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/setEnv.sh @@ -0,0 +1,17 @@ +# redis enterprise example +# export REDIS_HOST=redis-17794.jph.jphaugla.demo-rlec.redislabs.com +# export REDIS_PORT=17794 +export REDIS_HOST=localhost +export REDIS_PORT=6379 +export REDIS_PASSWORD=jasonrocks +export USE_SSL=false +# substitue in actual KAFKA_HOST internal IP +# this will not run using a public ip-use the private ip on app node. Did not set up the advertized listeners in kafka to make this work +export KAFKA_HOST=localhost +export KAFKA_PORT=9092 +export SPRING_CASSANDRA_HOST=localhost +export SPRING_CASSANDRA_PORT=9042 +# export SPRING_CASSANDRA_USER=cassandra +# export SPRING_CASSANDRA_PASSWORD=jph +export SPRING_CASSANDRA_CLUSTER=test +export SPRING_CASSANDRA_DATACENTER=datacenter1 diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/startAppServers.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/startAppServers.sh new file mode 100644 index 000000000..27d615730 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/startAppServers.sh @@ -0,0 +1,7 @@ +# start multiple app server instances for load testing +nohup java -DServer.port=8080 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8080.out 2>&1 & +nohup java -DServer.port=8081 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8081.out 2>&1 & +nohup java -DServer.port=8082 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8082.out 2>&1 & +nohup java -DServer.port=8083 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8083.out 2>&1 & +nohup java -DServer.port=8084 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8084.out 2>&1 & +nohup java -DServer.port=8085 -jar ../target/redis-0.0.1-SNAPSHOT.jar > /tmp/appServer8085.out 2>&1 & diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/testKafka.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/testKafka.sh new file mode 100644 index 000000000..2e5f6b2a3 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/testKafka.sh @@ -0,0 +1 @@ +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/send' diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/trans.cql b/jdk_17_maven/cs/rest/digitalbanking/scripts/trans.cql new file mode 100644 index 000000000..fa37df2c9 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/trans.cql @@ -0,0 +1 @@ +create table if not exists banking.transaction ( tranid text, accountno text, amounttype text, merchant text, referencekeytype text, referencekeyvalue text, originalamount text, amount text, trancd text, description text, initialdate text, settlementdate text, postingdate text, status text, disputeid text, transactionreturn text, location text, transactiontags text, primary key (tranid)); diff --git a/jdk_17_maven/cs/rest/digitalbanking/scripts/updateTransactionStatus.sh b/jdk_17_maven/cs/rest/digitalbanking/scripts/updateTransactionStatus.sh new file mode 100644 index 000000000..0d3af3f1c --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/scripts/updateTransactionStatus.sh @@ -0,0 +1,5 @@ +#not working +# generate new transactions to move all of one transaction +# Status up to the next transaction status. Parameter is target status. +# Can choose SETTLED or POSTED +curl -X GET -H "Content-Type: application/json" 'http://localhost:8080/statusChangeTransactions?transactionStatus=POSTED' diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/DemoApplication.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/DemoApplication.java new file mode 100644 index 000000000..3c52f4c0a --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/DemoApplication.java @@ -0,0 +1,25 @@ +package com.jphaugla; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@EnableKafka +@SpringBootApplication + + +public class DemoApplication extends SpringBootServletInitializer { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/boot/CreateIndexes.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/boot/CreateIndexes.java new file mode 100644 index 000000000..bda18d360 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/boot/CreateIndexes.java @@ -0,0 +1,167 @@ +package com.jphaugla.boot; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import redis.clients.jedis.ConnectionPoolConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.search.FieldName; +import redis.clients.jedis.search.IndexDefinition; +import redis.clients.jedis.search.IndexOptions; +import redis.clients.jedis.search.Schema; + +@Component +@Order(6) +@Slf4j +public class CreateIndexes implements CommandLineRunner { + + @Value("${app.accountSearchIndexName}") + private String accountSearchIndexName; + @Value("${app.customerSearchIndexName}") + private String customerSearchIndexName; + @Value("${app.emailSearchIndexName}") + private String emailSearchIndexName; + @Value("${app.merchantSearchIndexName}") + private String merchantSearchIndexName; + @Value("${app.phoneSearchIndexName}") + private String phoneSearchIndexName; + @Value("${app.transactionSearchIndexName}") + private String transactionSearchIndexName; + @Value("${app.transactionReturnSearchIndexName}") + private String transactionReturnSearchIndexName; + @Value("${app.disputeSearchIndexName}") + private String disputeSearchIndexName; + + @Autowired + private Environment env; + + UnifiedJedis client; + IndexDefinition.Type indexType = IndexDefinition.Type.HASH; + + @Override + @SuppressWarnings({ "unchecked" }) + public void run(String... args) throws Exception { + + client = jedis_connection(); + + Schema accountIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("customerId").as("customerId"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("accountType").as("accountType"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("accountOriginSystem").as("accountOriginSystem"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("accountStatus").as("accountStatus"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("cardNum").as("cardNum"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("openDate").as("openDate"), Schema.FieldType.NUMERIC)) + // .addField(new Schema.Field(FieldName.of( "lastUpdated").as("lastUpdated"), Schema.FieldType.NUMERIC)) + ; + tryIndex(client, accountSearchIndexName, accountIndexSchema); + + Schema customerIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("city").as("city"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("firstName").as("firstName"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("fullName").as("fullName"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("lastName").as("lastName"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("stateAbbreviation").as("stateAbbreviation"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("zipcode").as("zipcode"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("customerId").as("customerId"), Schema.FieldType.TAG)) + ; + tryIndex(client, customerSearchIndexName, customerIndexSchema); + + + Schema emailIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("emailAddress").as("emailAddress"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("customerId").as("customerId"), Schema.FieldType.TAG)) + ; + tryIndex(client, emailSearchIndexName, emailIndexSchema); + + Schema merchantIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("merchantName").as("merchantName"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("categoryCode").as("categoryCode"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("categoryDescription").as("categoryDescription"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("merchantState").as("merchantState"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("merchantCountry").as("merchantCountry"), Schema.FieldType.TAG)) + ; + tryIndex(client, merchantSearchIndexName, merchantIndexSchema); + + Schema phoneIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("phoneNumber").as("phoneNumber"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("customerId").as("customerId"), Schema.FieldType.TAG)) + ; + tryIndex(client, phoneSearchIndexName, phoneIndexSchema); + + Schema transactionIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("accountno").as("accountno"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("amounttype").as("amounttype"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("merchant").as("merchant"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("status").as("status"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("description").as("description"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("referencekeytype").as("referencekeytype"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("referencevalue").as("referencevalue"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("trancd").as("trancd"), Schema.FieldType.TAG)) + // .addField(new Schema.Field(FieldName.of("location").as("location"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("transactionreturn").as("transactionreturn"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("initialdate").as("initialdate"), Schema.FieldType.NUMERIC)) + .addField(new Schema.Field(FieldName.of( "settlementdate").as("settlementdate"), Schema.FieldType.NUMERIC)) + .addField(new Schema.Field(FieldName.of( "postingdate").as("postingdate"), Schema.FieldType.NUMERIC)) + .addField(new Schema.Field(FieldName.of("transactiontags").as("transactiontags"), Schema.FieldType.TAG)) + ; + tryIndex(client, transactionSearchIndexName, transactionIndexSchema); + + Schema transactionReturnIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("reasonCode").as("reasonCode"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("reasonDescription").as("reasonDescription"), Schema.FieldType.TAG)) + ; + tryIndex(client, transactionReturnSearchIndexName, transactionReturnIndexSchema); + Schema disputeIndexSchema = new Schema() + .addField(new Schema.Field(FieldName.of("reasonCode").as("reasonCode"), Schema.FieldType.TAG)) + .addField(new Schema.Field(FieldName.of("reasonDescription").as("reasonDescription"), Schema.FieldType.TAG)) + ; + tryIndex(client, disputeSearchIndexName, disputeIndexSchema); + } + public void tryIndex(UnifiedJedis jedis_client, String indexName, Schema schema) { + log.info("rebuilding index on " + indexName); + + IndexDefinition indexDefinition = new IndexDefinition(indexType).setPrefixes(indexName + ':'); + try { + jedis_client.ftCreate(indexName, IndexOptions.defaultOptions().setDefinition(indexDefinition), schema); + } catch (Exception e) { + jedis_client.ftDropIndex(indexName); + jedis_client.ftCreate(indexName, IndexOptions.defaultOptions().setDefinition(indexDefinition), schema); + } + + } + private UnifiedJedis jedis_connection() { + // Get the configuration from the application properties/environment + UnifiedJedis unifiedJedis; + String redisHost = "localhost"; // default name + int redisPort = 6379; + String redisPassword = ""; + + redisHost = env.getProperty("redis.host", "localhost"); + redisPort = Integer.parseInt(env.getProperty("redis.port", "6379")); + redisPassword = env.getProperty("spring.redis.password", ""); + + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxIdle(50); + poolConfig.setMaxTotal(50); + HostAndPort hostAndPort = new HostAndPort(redisHost, redisPort); + + log.info( "Host: " + redisHost + " Port " + String.valueOf(redisPort)); + if (!(redisPassword.isEmpty())) { + String redisURL = "redis://:" + redisPassword + '@' + redisHost + ':' + String.valueOf(redisPort); + log.info("redisURL is " + redisURL); + unifiedJedis = new JedisPooled(redisURL); + } else { + log.info(" no password"); + unifiedJedis = new JedisPooled(hostAndPort); + } + return unifiedJedis; + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/CassandraConfig.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/CassandraConfig.java new file mode 100644 index 000000000..30d03bae6 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/CassandraConfig.java @@ -0,0 +1,56 @@ +package com.jphaugla.config; + +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; + +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; +import org.springframework.data.cassandra.config.CqlSessionFactoryBean; + +import java.util.Arrays; +import java.util.List; + +@Configuration +@EnableCassandraRepositories(basePackages = {"com.jphaugla"}) +@ConfigurationProperties(prefix = "spring.data.cassandra") +@Getter +@Setter +@Slf4j +public class CassandraConfig extends AbstractCassandraConfiguration { + + @Value("${spring.data.cassandra.keyspace-name}") + private String keyspaceName; + @Value("${spring.data.cassandra.contact-points}") + private String contactPoints; + @Value("${spring.data.cassandra.port}") + private int port; + @Value("${spring.data.cassandra.local-datacenter}") + private String localDataCenter; + // @Value("${spring.data.cassandra.username}") + // private String username; + // @Value("${spring.data.cassandra.password}") + // private String password; + + + @Bean + @Override + public CqlSessionFactoryBean cassandraSession() { + CqlSessionFactoryBean cassandraSession = super.cassandraSession();//super session should be called only once + // cassandraSession.setUsername(username); + // cassandraSession.setPassword(password); + log.info("cassandra contact-points " + contactPoints); + log.info("cassandra data center " + localDataCenter); + // log.info("cassandra username " + username); + // log.info("cassandra password " + password); + log.info("cassandra keyspace " + keyspaceName); + log.info("cassandra port " + port); + return cassandraSession; + } + + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/RedisConfig.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/RedisConfig.java new file mode 100644 index 000000000..1f6aac94b --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/config/RedisConfig.java @@ -0,0 +1,133 @@ +package com.jphaugla.config; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.kafka.clients.admin.AdminClientConfig; +import org.apache.kafka.clients.admin.NewTopic; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.kafka.config.TopicBuilder; +import org.springframework.kafka.core.KafkaAdmin; +import redis.clients.jedis.JedisPoolConfig; + + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.beans.factory.annotation.Autowired; + +import org.springframework.data.redis.connection.RedisPassword; +import org.springframework.core.env.Environment; + +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.GenericToStringSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.core.task.TaskExecutor; +import org.springframework.context.annotation.Bean; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executor; +import java.time.Duration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +@Configuration +@EnableConfigurationProperties(RedisProperties.class) +@EnableAsync +@EnableRedisRepositories +@EnableAutoConfiguration +@ComponentScan("com.jphaugla") +@Slf4j +public class RedisConfig { + @Autowired + private Environment env; + private @Value("${spring.redis.timeout}") + Duration redisCommandTimeout; + + + @Bean(name = "redisConnectionFactory") + @Primary + public RedisConnectionFactory redisConnectionFactory() { + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxIdle(50); + poolConfig.setMaxTotal(50); + JedisClientConfiguration.JedisClientConfigurationBuilder clientConfig = JedisClientConfiguration.builder(); + clientConfig.usePooling().poolConfig(poolConfig); + JedisConnectionFactory jedisConnectionFactory; + RedisStandaloneConfiguration redisServerConf = new RedisStandaloneConfiguration(); + String hostname = env.getProperty("spring.redis.host", "localhost"); + String port = env.getProperty("spring.redis.port", "6379"); + String password = env.getProperty("spring.redis.password"); + redisServerConf.setHostName(hostname); + redisServerConf.setPort(Integer.parseInt(port)); + log.info("hostname is " + hostname + " port is " + port); + if(password != null && !password.isEmpty()) { + redisServerConf.setPassword(RedisPassword.of(password)); + log.info("password is " + password); + } + jedisConnectionFactory = new JedisConnectionFactory(redisServerConf, clientConfig.build()); + return jedisConnectionFactory; + } + + @Bean + @Primary + public RedisTemplate redisTemplateW1(@Qualifier("redisConnectionFactory") RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + // redisTemplate.setHashValueSerializer(new GenericToStringSerializer(Long.class)); + // redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); + redisTemplate.setHashValueSerializer(new StringRedisSerializer()); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + + @Bean("threadPoolTaskExecutor") + public TaskExecutor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); +// on large 64 core machine, drove setCorePoolSize to 200 to really spike performance + executor.setCorePoolSize(100); + executor.setMaxPoolSize(1000); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setThreadNamePrefix("Async-"); + return executor; + } + /* @Bean + public KafkaAdmin admin() + { + Map configs = new HashMap<>(); + String kafkaBootstrap = env.getProperty("spring.kafka.producer.bootstrap-servers"); + configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, + kafkaBootstrap); + return new KafkaAdmin(configs); + } + @Bean + public NewTopic topic1() + { + String topic_name=env.getProperty("topic.name.producer"); + return TopicBuilder.name(topic_name) + .partitions(1) + .replicas(1) + .build(); + } + + */ +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/controller/BankingController.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/controller/BankingController.java new file mode 100644 index 000000000..af86560d4 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/controller/BankingController.java @@ -0,0 +1,274 @@ +package com.jphaugla.controller; + +import java.text.ParseException; +import java.util.*; +import java.util.concurrent.ExecutionException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.jphaugla.domain.*; +import com.jphaugla.service.TopicProducer; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.*; + +import com.jphaugla.service.BankService; +import redis.clients.jedis.search.SearchResult; + + +@RequiredArgsConstructor +@RestController +public class BankingController { + + @Autowired + private BankService bankService = BankService.getInstance(); + + private static final Logger logger = LoggerFactory.getLogger(BankingController.class); + private final TopicProducer topicProducer; + // customer + @RequestMapping("/save_customer") + public String saveCustomer() throws ParseException { + bankService.saveSampleCustomer(); + return "Done"; + } +// test send message + @GetMapping (value = "/send") + public void send() throws ExecutionException, InterruptedException { + topicProducer.send("Mensagem de teste enviada ao tópico", "mensagem"); + } + // account + @RequestMapping("/save_account") + public String saveAccount() throws ParseException { + bankService.saveSampleAccount(); + return "Done"; + } + + // transaction + @RequestMapping("/save_transaction") + public String saveTransaction(@RequestParam Boolean doKafka) throws ParseException, JsonProcessingException { + logger.info("starting save transaction with doKafka:" + doKafka); + bankService.saveSampleTransaction(doKafka); + return "Done"; + } + + @GetMapping("/generateData") + @ResponseBody + public String generateData (@RequestParam Integer noOfCustomers, @RequestParam Integer noOfTransactions, + @RequestParam Integer noOfDays, @RequestParam String key_suffix, + @RequestParam Boolean doKafka) + throws ParseException, ExecutionException, InterruptedException, IllegalAccessException, JsonProcessingException { + logger.info("starting generate data with doKafka=" + doKafka); + bankService.generateData(noOfCustomers, noOfTransactions, noOfDays, key_suffix, doKafka); + + return "Done"; + } + + @GetMapping("/testPipeline") + @ResponseBody + public String testPipeline (@RequestParam Integer noOfRecords) + throws ParseException, ExecutionException, InterruptedException, IllegalAccessException { + + // bankService.testPipeline(noOfRecords); + + return "Done"; + } + @GetMapping("/customerByPhone") + + public Customer getCustomerByPhone(@RequestParam String phoneString) { + logger.debug("In get customerByPhone with phone as " + phoneString); + return bankService.getCustomerByPhone(phoneString); + } + + @GetMapping("/customerByEmail") + + public Customer getCustomerByEmail(@RequestParam String email) { + logger.debug("IN get customerByEmail, email is " + email); + return bankService.getCustomerByEmail(email); + } + + + @GetMapping("/customerByStateCity") + + public SearchResult getCustomerByStateCity(@RequestParam String state, @RequestParam String city) { + logger.debug("IN get customerByState with state as " + state + " and city=" + city); + return bankService.getCustomerByStateCity(state, city); + } + @GetMapping("/customerByZipcodeLastname") + + public SearchResult getCustomerIdsbyZipcodeLastname(@RequestParam String zipcode, @RequestParam String lastname) { + logger.debug("IN get getCustomerIdsbyZipcodeLastname with zipcode as " + zipcode + " and lastname=" + lastname); + return bankService.getCustomerIdsbyZipcodeLastname(zipcode, lastname); + } + @GetMapping("/merchantCategoryTransactions") + + public SearchResult getMerchantCategoryTransactions + (@RequestParam String merchantCategory, @RequestParam String account, + @RequestParam(name = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date startDate, + @RequestParam(name = "to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date endDate) + throws ParseException { + logger.debug("In getMerchantCategoryTransactions merchantCategory=" + merchantCategory + " account=" + account + + " from=" + startDate + " to=" + endDate); + return bankService.getMerchantCategoryTransactions(merchantCategory, account, startDate, endDate); + } + @GetMapping("/merchantTransactions") + + public SearchResult getMerchantTransactions + (@RequestParam String merchant, @RequestParam String account, + @RequestParam(name = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date startDate, + @RequestParam(name = "to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date endDate) + throws ParseException { + logger.info("In getMerchantTransactions merchant=" + merchant + " account=" + account + + " from=" + startDate + " to=" + endDate); + return bankService.getMerchantTransactions(merchant, account, startDate, endDate); + } + + + @GetMapping ("/transactionStatusReport") + + public List> transactionStatusReport () { + return bankService.transactionStatusReport(); + + } + + + @GetMapping("/returned_transactions") + + public SearchResult getReturnedTransaction () { + logger.info("in bankcontroller getReturnedTransaction"); + return bankService.getTransactionReturns(); + } + /* + + @GetMapping("/statusChangeTransactions") + + public AggregateResults generateStatusChangeTransactions(@RequestParam String transactionStatus) + throws ParseException, IllegalAccessException, ExecutionException, InterruptedException { + logger.info("generateStatusChangeTransactions transactionStatus=" + transactionStatus); + AggregateResults changeReport = new AggregateResults<>(); + + changeReport.addAll(transactionStatusReport()); + bankService.transactionStatusChange(transactionStatus); + changeReport.addAll(transactionStatusReport()); + + return changeReport; + + } + */ + + @GetMapping("/creditCardTransactions") + + public SearchResult getCreditCardTransactions + (@RequestParam String creditCard, + @RequestParam(name = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date startDate, + @RequestParam(name = "to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date endDate) + throws ParseException { + logger.debug("getCreditCardTransactions creditCard=" + creditCard + + " startDate=" + startDate + " endDate=" + endDate); + return bankService.getCreditCardTransactions(creditCard, startDate, endDate); + } + + @GetMapping("/accountTransactions") + + public SearchResult getAccountTransactions + (@RequestParam String accountNo, + @RequestParam(name = "from") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date startDate, + @RequestParam(name = "to") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date endDate) + throws ParseException { + logger.debug("getCreditCardTransactions creditCard=" + accountNo + + " startDate=" + startDate + " endDate=" + endDate); + return bankService.getAccountTransactions(accountNo, startDate, endDate); + + } + + @GetMapping("/addTag") + + public void addTag(@RequestParam String transactionID, + @RequestParam String tag, @RequestParam String operation) { + logger.debug("addTags with transactionID=" + transactionID + " tag is " + tag + " operation is " + operation); + bankService.addTag(transactionID, tag, operation); + } + + @GetMapping("/getTags") + public HashSet getTransactionTagList(@RequestParam String transactionID) { + logger.debug("getTags with transactionID=" + transactionID); + return bankService.getTransactionTagList(transactionID); + } + + @GetMapping("/getTaggedTransactions") + + public SearchResult getTaggedTransactions + (@RequestParam String accountNo, @RequestParam String tag) + throws ParseException { + logger.debug("In getTaggedTransactions accountNo=" + accountNo + " tag=" + tag ); + return bankService.getTaggedTransactions(accountNo, tag); + } + @GetMapping("/getTransaction") + public Transaction getTransaction(@RequestParam String transactionID) { + Transaction transaction = bankService.getTransaction(transactionID); + return transaction; + } + @GetMapping("/mostRecentTransactions") + + public SearchResult mostRecentTransactions + (@RequestParam String accountNo) + throws ParseException { + logger.debug("In mostRecentTransactions accountNo=" + accountNo ); + return bankService.mostRecentTransactions(accountNo); + } + + @GetMapping("/customer") + + public Optional getCustomer(@RequestParam String customerId) { + return bankService.getCustomer(customerId); + } + + @GetMapping("/deleteCustomer") + + public int deleteCustomer(@RequestParam String customerString) { + return bankService.deleteCustomer(customerString); + } + + @GetMapping("/deleteCustomerEmail") + + public int deleteCustomerEmail(@RequestParam String customerId) { + return bankService.deleteCustomerEmail(customerId); + } + + @PostMapping(value = "/postCustomer", consumes = "application/json", produces = "application/json") + public String postCustomer(@RequestBody Customer customer ) throws ParseException { + bankService.postCustomer(customer); + return "Done\n"; + } + + @PostMapping(value = "/postDispute", consumes = "application/json", produces = "application/json") + public String postDispute(@RequestBody Dispute dispute ) throws ParseException { + bankService.postDispute(dispute); + return "Done\n"; + } + + @PutMapping(value = "/putDisputeChargeBackReason", consumes = "application/json", produces = "application/json") + public String putDisputeChargeBackReason(@RequestParam String disputeId, @RequestParam String reasonCode ) { + bankService.putDisputeChargeBackReason(disputeId, reasonCode); + return "Done\n"; + } + + @PutMapping(value = "/acceptDispute", consumes = "application/json", produces = "application/json") + public String acceptDisputeChargeBack(@RequestParam String disputeId) { + bankService.acceptDisputeChargeBack(disputeId); + return "Done\n"; + } + + @PutMapping(value = "/resolvedDispute", consumes = "application/json", produces = "application/json") + public String resolvedDispute(@RequestParam String disputeId ) { + bankService.resolvedDispute(disputeId); + return "Done\n"; + } + @GetMapping("/getDispute") + + public Dispute getDispute(@RequestParam String disputeId) { + return bankService.getDispute(disputeId); + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/data/BankGenerator.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/data/BankGenerator.java new file mode 100644 index 000000000..ed3868ace --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/data/BankGenerator.java @@ -0,0 +1,355 @@ +package com.jphaugla.data; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +import com.jphaugla.domain.*; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BankGenerator { + // private static final Logger logger = LoggerFactory.getLogger(BankGenerator.class); + private static final int BASE = 1000000; + private static final int DAY_MILLIS = 1000 * 60 *60 * 24; + private static AtomicInteger customerIdGenerator = new AtomicInteger(1); + private static AtomicInteger accountNoGenerator = new AtomicInteger(1); + private static List accountTypes = Arrays.asList("Current", "Joint Current", "Saving", "Mortgage", + "E-Saving", "Deposit"); + private static List accountIds = new ArrayList(); + private static Map> accountsMap = new HashMap>(); + + //We can change this from the Main + public static DateTime date = new DateTime().minusDays(180).withTimeAtStartOfDay(); + public static Date currentDate = new Date(); + public static String timeStamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(currentDate); + + public static List whiteList = new ArrayList(); + + public static String getRandomCustomerId(int noOfCustomers){ + int max = noOfCustomers + 1; + int min = 1; + int random_int = (int)Math.floor(Math.random() * (max - min +1) + min); + return BASE + Integer.toString(random_int); + // return BASE + new Double(Math.random()*noOfCustomers).intValue() + ""; + } + + public static List createEmail (String customerId) { + Email home_email = new Email(customerId + "@gmail.com","home", customerId); + Email work_email = new Email(customerId + "@BigCompany.com","work", customerId); + List emailList; + emailList = new ArrayList(); + emailList.add(home_email); + emailList.add(work_email); + return emailList; + } + + public static List createPhone (String customerId) { + Phone home_phone = new Phone(customerId + "h", "home", customerId); + Phone cell_phone = new Phone(customerId + "c", "cell", customerId); + Phone workPhone = new Phone(customerId + "w", "work", customerId); + List phoneList; + phoneList = new ArrayList(); + phoneList.add(home_phone); + phoneList.add(cell_phone); + phoneList.add(workPhone); + return phoneList; + } + + public static Customer createRandomCustomer(String key_suffix) { + + String customerIdInt = BASE + customerIdGenerator.getAndIncrement() + ""; + String customerId = customerIdInt + key_suffix; + + Customer customer = new Customer(); + customer.setCustomerId(customerId); + + customer.setAddressLine1("Line1-" + customerId); + customer.setCreatedBy("Java Test"); + customer.setLastUpdatedBy("Java Test"); + customer.setCustomerType("Retail"); + + customer.setCreatedDatetime(Long.toString(currentDate.getTime())); + customer.setLastUpdated(Long.toString(currentDate.getTime())); + + customer.setCustomerOriginSystem("RCIF"); + customer.setCustomerStatus("A"); + customer.setCountryCode("00"); + customer.setGovernmentId("TIN"); + customer.setGovernmentIdType(customerIdInt.substring(1)); + + int lastDigit = Integer.parseInt(customerIdInt.substring(6)); + if (lastDigit>7) { + customer.setAddressLine2("Apt " + customerId); + customer.setAddressType("Apartment"); + customer.setBillPayEnrolled("false"); + } + else if (lastDigit==3){ + customer.setBillPayEnrolled("false"); + customer.setAddressType("Mobile"); + } + else { + customer.setAddressType("Residence"); + customer.setBillPayEnrolled("true"); + } + customer.setCity(locations.get(lastDigit)); + customer.setStateAbbreviation(States[lastDigit]); + customer.setDateOfBirth(dob.get(lastDigit)); + String lastName = customerId.substring(2,7); + String firstName = firstList.get(lastDigit); + String middleName = middleList.get(lastDigit); + customer.setGender(genderList[lastDigit]); + if (genderList[lastDigit]=="F"){ + customer.setPrefix("Ms"); + } + else { + customer.setPrefix("Mr"); + } + String zipChar = zipcodeList.get(lastDigit).toString(); + customer.setZipcode(zipChar); + customer.setZipcode4(zipChar + "-1234"); + customer.setFirstName(firstName); + customer.setLastName(lastName); + customer.setMiddleName(middleName); + customer.setFullName(firstName + " " + middleName + " " + lastName); + + + return customer; + } + public static List createMerchantList () { + List merchants = new ArrayList<>(); + int iterations = issuers.length; + for (int i=0; i < iterations; i++) { + merchants.add(new Merchant(issuers[i], issuersCD[i], issuersCDdesc[i], States[i],"US")); + } + return merchants; + }; + public static List createMerchantName () { + List merchants = new ArrayList<>(); + // for(String merchant:issuers) { + merchants = Arrays.asList(issuers); + return merchants; + } + + public static List createTransactionReturnList() { + List transactionReturns = new ArrayList<>(); + transactionReturns.add(new TransactionReturn("1345","incorrect amount recorded")); + transactionReturns.add(new TransactionReturn("1554","not authorized transaction")); + transactionReturns.add(new TransactionReturn("6555","wrong account")); + return transactionReturns; + }; + + public static List createRandomAccountsForCustomer(Customer customer, String key_suffix) { + + int noOfAccounts = Math.random() < .1 ? 4 : 3; + List accounts = new ArrayList(); + + + for (int i = 0; i < noOfAccounts; i++){ + + Account account = new Account(); + String accountNumber = "Acct" + accountNoGenerator.getAndIncrement() + "" + key_suffix; + // String accountNumber = "Acct" + Integer.toString(i) + key_suffix; + account.setCardNum( UUID.randomUUID().toString().replace('-','x')); + account.setCustomerId(customer.getCustomerId()); + account.setAccountNo(accountNumber); + account.setAccountType(accountTypes.get(i)); + account.setAccountStatus("Open"); + account.setLastUpdatedBy("Java Test"); + account.setLastUpdated(Long.toString(currentDate.getTime())); + account.setCreatedDatetime(Long.toString(currentDate.getTime())); + account.setCreatedBy("Java Test"); + + + accounts.add(account); + + //Keep a list of all Account Nos to create the transactions + accountIds.add(account.getAccountNo()); + } + + return accounts; + } + public static Transaction createRandomTransaction(int noOfDays, Integer idx, Account account, + String key_suffix, List merchants, + List transactionReturns) { + + int noOfMillis = noOfDays * DAY_MILLIS; + // create time by adding a random no of millis + double v = Math.random() * noOfMillis; + int intValue = (int) v; + DateTime newDate = date.plusMillis(intValue); + + return createRandomTransaction(newDate, idx, account, key_suffix, merchants, transactionReturns); + } + public static Transaction createRandomTransaction(DateTime newDate, Integer idx, Account account, + String key_suffix,List merchants, + List transactionReturns) { + double v = Math.random() * locations.size(); + int intValue = (int) v; + String location = locations.get(intValue); + v = Math.ceil(Math.random() * 3); + int noOfItems = (int) v; + v = Math.random() * issuers.length; + int randomLocation = (int) v; + + Date aNewDate = newDate.toDate(); + Date oldDate = new Date(0); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(aNewDate); + calendar.add(Calendar.DATE, -1); + Date date_minus_one =calendar.getTime(); + calendar.add(Calendar.DATE, -1); + Date date_minus_two = calendar.getTime(); + + Transaction transaction = new Transaction(); + createItemsAndAmount(noOfItems, transaction); + transaction.setAccountno(account.getAccountNo()); + // String tran_id = "{" + account.getAccountNo() + "}" + idx.toString() + key_suffix; + String tran_id = idx.toString() + key_suffix; + transaction.setTranid(tran_id); + String transactionStat = transactionStatus[randomLocation]; + transaction.setStatus(transactionStat); + if(transactionStat == "POSTED") { + transaction.setPostingdate(Long.toString(aNewDate.getTime())); + transaction.setSettlementdate(Long.toString(date_minus_one.getTime())); + transaction.setInitialdate(Long.toString(date_minus_two.getTime())); + } else if (transactionStat == "SETTLED") { + transaction.setSettlementdate(Long.toString(aNewDate.getTime())); + transaction.setInitialdate(Long.toString(date_minus_one.getTime())); + transaction.setPostingdate(Long.toString(oldDate.getTime())); + } else { + transaction.setInitialdate(Long.toString(aNewDate.getTime())); + transaction.setPostingdate(Long.toString(oldDate.getTime())); + transaction.setSettlementdate(Long.toString(oldDate.getTime())); + } + transaction.setLocation(location); + if(randomLocation<5) { + transaction.setAmounttype("Debit"); + } + else{ + transaction.setAmounttype("Credit"); + } + transaction.setMerchant(merchants.get(randomLocation).getName()); + + transaction.setReferencekeytype("reftype"); + transaction.setReferencekeyvalue("thisRef"); + + transaction.setTrancd(issuersCD[randomLocation]); + transaction.setDescription("description" + issuersCD[randomLocation] + genderList[randomLocation/3 + 1]); + if(randomLocation==8) { + transaction.setTransactionreturn(transactionReturns.get(0).getReasonCode()); + } else if (randomLocation == 13) { + transaction.setTransactionreturn(transactionReturns.get(1).getReasonCode()); + } + return transaction; + } + + /** + * Creates a random transaction with some skew for some accounts. + * @return + */ + + private static void createItemsAndAmount(int noOfItems, Transaction transaction) { + Map items = new HashMap(); + double totalAmount = 0; + + for (int i = 0; i < noOfItems; i++) { + + double amount = Math.random() * 100; + items.put("item" + i, amount); + + totalAmount += amount; + } + transaction.setAmount(String.valueOf(totalAmount)); + transaction.setOriginalamount(String.valueOf(totalAmount)); + } + + + public static class Timer { + + private long timeTaken; + private long start; + + public Timer(){ + start(); + } + public void start(){ + this.start = System.currentTimeMillis(); + } + public void end(){ + this.timeTaken = System.currentTimeMillis() - start; + } + + public long getTimeTakenMillis(){ + return this.timeTaken; + } + + public int getTimeTakenSeconds(){ + double v = (double) this.timeTaken / 1000; + return ((int) v); + } + + public String getTimeTakenMinutes(){ + double v = (double) this.timeTaken / (1000*60); + return String.format("%1$,.2f", v); + } + + } + + + public static List locations = Arrays.asList("Chicago", "Minneapolis", "St. Paul", "Plymouth", "Edina", + "Duluth", "Bloomington", "Bloomington", "Rockford", "Champaign"); + public static List zipcodeList = Arrays.asList(60601, 55401, 55101, 55441, 55435, + 55802, 61704, 55435, 61101, 16821); + public static List dob = Arrays.asList("08/19/1964", "07/14/1984", "01/20/2000", "06/10/1951", "11/22/1995", + "12/13/1954", "08/12/1943", "11/29/1964", "02/01/1994", "07/12/1944"); + public static String[] transactionStatus = {"POSTED", "AUTHORIZED", "SETTLED", "POSTED", "POSTED", "POSTED", + "POSTED", "POSTED", "POSTED", "POSTED", "POSTED", "POSTED", + "POSTED", "POSTED", "POSTED", "POSTED", "POSTED", "POSTED", + "AUTHORIZED", "SETTLED","POSTED","AUTHORIZED","SETTLED","POSTED","POSTED","POSTED"}; + public static String[] States = {"IL", "MN", "MN", "MN", "MN","CA", "AZ", "AL", "AK", "TX", "WY", "PR", + "MN", "IL", "MN", "MN", "IL", "IA", "WI", "SD", "ND", "MD", "CT", "WI", "KS", "IN","DE","TN" + }; + + public static String[] genderList = {"M", "F", "F", "M", "F", "F", "M", "M", "M", "F"}; + + public static List middleList = Arrays.asList("Paul", "Ann", "Mary", "Joseph", "Amy", + "Elizabeth", "John", "Javier", "Golov", "Eliza"); + + public static List firstList = Arrays.asList("Jason", "Catherine", "Esmeralda", "Marcus", "Louisa", + "Julia", "Miles", "Luis", "Igor", "Angela"); + + public static String[] issuers = {"Tesco", "Sainsbury", "Wal-Mart Stores", "Morrisons", + "Marks & Spencer", "Walmart", "John Lewis", "Cub Foods", "Argos", "Co-op", "Currys", "PC World", "B&Q", + "Somerfield", "Next", "Spar", "Amazon", "Costa", "Starbucks", "BestBuy", "Lowes", "BarnesNoble", + "Carlson Wagonlit Travel", "Pizza Hut", "Local Pub"}; + + public static String[] issuersCD = {"5411", "5411", "5310", "5499", + "5310", "5912", "5311", "5411", "5961", "5300", "5732", "5964", "5719", + "5411", "5651", "5411", "5310", "5691", "5814", "5732", "5211", "5942", "5962", + "5814", "5813"}; + + public static String[] issuersCDdesc = {"Grocery Stores", "Grocery Stores", + "Discount Stores", "Misc Food Stores Convenience Stores and Specialty Markets", + "Discount Stores", "Drug Stores and Pharmacies", "Department Stores", "Supermarkets", "Mail Order Houses", + "Wholesale Clubs", "Electronic Sales", + "Direct Marketing Catalog Merchant", "Miscellaneous Home Furnishing Specialty Stores", + "Grocery Stores", "Family Clothing Stores", "Grocery Stores", "Discount Stores", + "Mens and Womens Clothing Stores", + "Fast Food Restaurants", + "Electronic Sales", + "Lumber and Building Materials Stores", + "Book Stores", "Direct Marketing Travel Related Services", + "Fast Food Restaurants", "Drinking Places, Bars, Taverns, Cocktail lounges, Nightclubs and Discos"}; + + + public static List notes = Arrays.asList("Shopping", "Shopping", "Shopping", "Shopping", "Shopping", + "Pharmacy", "HouseHold", "Shopping", "Household", "Shopping", "Tech", "Tech", "Diy", "Shopping", "Clothes", + "Shopping", "Amazon", "Coffee", "Coffee", "Tech", "Diy", "Travel", "Travel", "Eating out", "Eating out"); + + public static List tagList = Arrays.asList("Home", "Home", "Home", "Home", "Home", "Home", "Home", "Home", + "Work", "Work", "Work", "Home", "Home", "Home", "Work", "Work", "Home", "Work", "Work", "Work", "Work", + "Work", "Work", "Work", "Work", "Expenses", "Luxury", "Entertaining", "School"); + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Account.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Account.java new file mode 100644 index 000000000..abd29e35d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Account.java @@ -0,0 +1,28 @@ +package com.jphaugla.domain; + +import lombok.*; + +import java.io.Serializable; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + + +public class Account implements Serializable { + private String accountNo; + private String customerId; + private String accountType; + private String accountOriginSystem; + private String accountStatus; + private String cardNum; + private String openDatetime; + private String lastUpdated; + private String lastUpdatedBy; + private String createdBy; + private String createdDatetime; +} + diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/CassandraTransaction.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/CassandraTransaction.java new file mode 100644 index 000000000..48ce60672 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/CassandraTransaction.java @@ -0,0 +1,39 @@ +package com.jphaugla.domain; + +import lombok.*; +import org.springframework.data.cassandra.core.mapping.PrimaryKey; +import org.springframework.data.cassandra.core.mapping.Table; + +import java.io.Serializable; + +@Data +@Table +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + +public class CassandraTransaction implements Serializable { + @PrimaryKey + private String tranid; + private String accountno; + // debit or credit + private String amounttype; + private String merchant; + private String referencekeytype; + private String referencekeyValue; + private String originalamount; + private String amount; + private String trancd ; + private String description; + private String initialdate; + private String settlementdate; + private String postingdate; + // this is authorized, posted, settled + private String status ; + private String disputeid; + private String transactionreturn; + private String location; + private String transactiontags; + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Customer.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Customer.java new file mode 100644 index 000000000..785323fec --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Customer.java @@ -0,0 +1,42 @@ +package com.jphaugla.domain; + +import lombok.*; +import java.io.Serializable; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + + +public class Customer implements Serializable { + private String customerId; + private String addressLine1; + private String addressLine2; + private String addressType; + private String billPayEnrolled; + private String city; + private String countryCode; + private String createdBy; + private String createdDatetime; + private String customerOriginSystem; + private String customerStatus; + private String customerType; + private String dateOfBirth; + private String firstName; + private String fullName; + private String gender; + private String governmentId; + private String governmentIdType; + private String lastName; + private String lastUpdated; + private String lastUpdatedBy; + private String middleName; + private String prefix; + private String queryHelperColumn; + private String stateAbbreviation; + private String zipcode; + private String zipcode4; +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Dispute.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Dispute.java new file mode 100644 index 000000000..389c1b81e --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Dispute.java @@ -0,0 +1,22 @@ +package com.jphaugla.domain; + +import lombok.*; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class Dispute { + private String disputeId; + private String tranId; + private String filingDate; + private String reviewDate; + private String reasonCode; + private String acceptanceChargeBackDate; + private String resolutionDate; + private String lastUpdateDate; + private String status; + private String chargeBackAmount; + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Email.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Email.java new file mode 100644 index 000000000..d8528fa55 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Email.java @@ -0,0 +1,15 @@ +package com.jphaugla.domain; +import lombok.*; +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + +public class Email implements Serializable { + private String emailAddress; + private String emailLabel; + private String customerId; +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Merchant.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Merchant.java new file mode 100644 index 000000000..bd3118607 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Merchant.java @@ -0,0 +1,20 @@ +package com.jphaugla.domain; + +import lombok.*; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + +public class Merchant implements Serializable { + + private String name; + private String categoryCode; + private String categoryDescription; + private String state; + private String countryCode; +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Phone.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Phone.java new file mode 100644 index 000000000..527f6dff7 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Phone.java @@ -0,0 +1,18 @@ +package com.jphaugla.domain; +import lombok.*; + +import java.io.Serializable; + + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + +public class Phone implements Serializable { + + private String phoneNumber; + private String phoneLabel; + private String customerId; +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Transaction.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Transaction.java new file mode 100644 index 000000000..d8977b810 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/Transaction.java @@ -0,0 +1,42 @@ +package com.jphaugla.domain; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; +import org.springframework.data.cassandra.core.mapping.PrimaryKey; +import org.springframework.data.cassandra.core.mapping.Table; + + +import java.io.Serializable; + +@Data +@Table +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter + + +public class Transaction implements Serializable { + @PrimaryKey + private String tranid; + private String accountno; + // debit or credit + private String amounttype; + private String merchant; + private String referencekeytype; + private String referencekeyvalue; + private String originalamount; + private String amount; + private String trancd; + private String description; + private String initialdate; + private String settlementdate; + private String postingdate; + // this is authorized, posted, settled + private String status ; + private String disputeid; + private String transactionreturn; + private String location; + private String transactiontags; + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/TransactionReturn.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/TransactionReturn.java new file mode 100644 index 000000000..44cb72b03 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/domain/TransactionReturn.java @@ -0,0 +1,18 @@ +package com.jphaugla.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor + +public class TransactionReturn implements Serializable { + + private String reasonCode; + private String reasonDescription; +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/AccountRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/AccountRepository.java new file mode 100644 index 000000000..e5ebd5970 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/AccountRepository.java @@ -0,0 +1,86 @@ +package com.jphaugla.repository; +import com.jphaugla.domain.Account; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import com.jphaugla.domain.Account; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository +public class AccountRepository { + + @Autowired + ObjectMapper objectMapper; + + @Autowired + @Qualifier("redisTemplateW1") + private RedisTemplate redisTemplateW1; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + @Value("${app.accountSearchIndexName}") + private String accountSearchIndexName; + + public AccountRepository() { + + log.info("AccountRepository constructor"); + } + + public String create(Account account) { + log.info("AccountRepository create with index=" + accountSearchIndexName); + log.info(" account " + account.toString()); + if (account.getCreatedDatetime() == null) { + long currentTimeMillis = System.currentTimeMillis(); + String stringMillis = Long.toString(currentTimeMillis); + account.setCreatedDatetime(stringMillis); + account.setOpenDatetime(stringMillis); + account.setLastUpdated(stringMillis); + } + + Map AccountHash = objectMapper.convertValue(account, Map.class); + // while (AccountHash.values().remove(null)); + // logger.info( "before null removal with AccountHash " + AccountHash.toString()); + AccountHash.values().removeIf(Objects::isNull); + + // logger.info( "before putall with AccountHash " + AccountHash.toString()); + stringRedisTemplate.opsForHash().putAll(makeKey(account.getAccountNo()), AccountHash); + // redisTemplate.opsForHash().putAll("Account:" + Account.getAccountId(), AccountHash); + // logger.info(String.format("Account with ID %s saved", account.getAccountNo())); + return "Success\n"; + } + + public Account get(String accountId) { + log.info("in AccountRepository.get with Account id=" + accountId); + String fullKey = makeKey(accountId); + Map AccountHash = stringRedisTemplate.opsForHash().entries(fullKey); + Account account = objectMapper.convertValue(AccountHash, Account.class); + return (account); + } + + + public void createAll(List accounts) { + for (Account account : accounts) { + create(account); + } + } + + private String makeKey(String accountId) { + return accountSearchIndexName + ':' + accountId; + } +} \ No newline at end of file diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CassandraTransRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CassandraTransRepository.java new file mode 100644 index 000000000..61ea83522 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CassandraTransRepository.java @@ -0,0 +1,12 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.CassandraTransaction; +import com.jphaugla.domain.Transaction; +import org.springframework.data.cassandra.repository.CassandraRepository; + + +import java.util.UUID; + +public interface CassandraTransRepository extends CassandraRepository { + +} \ No newline at end of file diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CustomerRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CustomerRepository.java new file mode 100644 index 000000000..1713420e1 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/CustomerRepository.java @@ -0,0 +1,69 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Customer; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.util.Map; +import java.util.Objects; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository + +public class CustomerRepository{ + + + final Logger logger = LoggerFactory.getLogger(CustomerRepository.class); + @Autowired + ObjectMapper objectMapper; + + @Value("${app.customerSearchIndexName}") + private String customerSearchIndexName; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public CustomerRepository() { + + logger.info("CustomerRepository constructor"); + } + + public String create(Customer customer) { + if (customer.getCreatedDatetime() == null) { + Long currentTimeMillis = System.currentTimeMillis(); + customer.setCreatedDatetime(Long.toString(currentTimeMillis)); + customer.setLastUpdated(Long.toString(currentTimeMillis)); + } + + Map customerHash = objectMapper.convertValue(customer, Map.class); + customerHash.values().removeIf(Objects::isNull); + + stringRedisTemplate.opsForHash().putAll(makeKey(customer.getCustomerId()), customerHash); + // redisTemplate.opsForHash().putAll("Customer:" + customer.getCustomerId(), customerHash); + // logger.info(String.format("Customer with ID %s saved", customer.getCustomerId())); + return "Success\n"; + } + + public Customer get(String customerId) { + // logger.info("in CustomerRepository.get with customer id=" + customerId); + String fullKey = makeKey(customerId); + Map customerHash = stringRedisTemplate.opsForHash().entries(fullKey); + Customer customer = objectMapper.convertValue(customerHash, Customer.class); + return (customer); + } + private String makeKey(String customerId) { + return customerSearchIndexName + ':' + customerId; + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/DisputeRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/DisputeRepository.java new file mode 100644 index 000000000..34c64555b --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/DisputeRepository.java @@ -0,0 +1,85 @@ +package com.jphaugla.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import com.jphaugla.domain.Dispute; +import lombok.extern.slf4j.Slf4j; + + +import java.util.Map; +import java.util.Objects; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository + +public class DisputeRepository{ + + + @Autowired + ObjectMapper objectMapper; + + @Value("${app.disputeSearchIndexName}") + private String disputeSearchIndexName; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public DisputeRepository() { + + log.info("DisputeRepository constructor"); + } + + private String makeKey(String disputeId) { + return (disputeSearchIndexName + ':' + disputeId); + } + + public String create(Dispute dispute) { + if (dispute.getFilingDate() == null) { + Long currentTimeMillis = System.currentTimeMillis(); + dispute.setFilingDate(Long.toString(currentTimeMillis)); + dispute.setLastUpdateDate(Long.toString(currentTimeMillis)); + } + + Map DisputeHash = objectMapper.convertValue(dispute, Map.class); + DisputeHash.values().removeIf(Objects::isNull); + String fullKey = makeKey(dispute.getDisputeId()); + stringRedisTemplate.opsForHash().putAll(makeKey(dispute.getDisputeId()), DisputeHash); + log.info(String.format("Dispute with ID %s saved", fullKey)); + return "Success\n"; + } + + public Dispute get(String disputeId) { + // logger.info("in DisputeRepository.get with Dispute id=" + DisputeId); + Map DisputeHash = stringRedisTemplate.opsForHash().entries(makeKey(disputeId)); + Dispute dispute = objectMapper.convertValue(DisputeHash, Dispute.class); + return (dispute); + } + + public void setChargeBackReason(String disputeId, String chargeBackReason) { + Long currentTimeMillis = System.currentTimeMillis(); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"lastUpdateDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"reasonCode", chargeBackReason); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"reviewDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"status", "Investigate"); + } + + public void acceptChargeBack(String disputeId) { + Long currentTimeMillis = System.currentTimeMillis(); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"lastUpdateDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"acceptChargeBackDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"status", "ChargedBack"); + } + public void resolved(String disputeId) { + Long currentTimeMillis = System.currentTimeMillis(); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"lastUpdateDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"resolutionDate", Long.toString(currentTimeMillis)); + stringRedisTemplate.opsForHash().put(makeKey(disputeId),"status", "Resolved"); + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/EmailRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/EmailRepository.java new file mode 100644 index 000000000..3953be6d5 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/EmailRepository.java @@ -0,0 +1,89 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Email; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + + +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; + + +@Slf4j +@Repository + +public class EmailRepository{ + + @Autowired + ObjectMapper objectMapper; + + @Autowired + @Qualifier("redisTemplateW1") + private RedisTemplate redisTemplateW1; + @Value("${app.emailSearchIndexName}") + private String emailSearchIndexName; + @Value("${app.customerSearchIndexName}") + private String customerSearchIndexName; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public EmailRepository() { + + log.info("EmailRepository constructor"); + } + + public String create(Email email) { + + Map emailHash = objectMapper.convertValue(email, Map.class); + stringRedisTemplate.opsForHash().putAll(makeKey( email.getEmailAddress()), emailHash); + // for demo purposed add a member to the set for the Customer + stringRedisTemplate.opsForSet().add("CustEmail:" + email.getCustomerId(), email.getEmailAddress()); + // redisTemplate.opsForHash().putAll("Email:" + email.getEmailId(), emailHash); + // logger.info(String.format("Email with ID %s saved", email.getEmailAddress())); + return "Success\n"; + } + + public Email get(String emailId) { + log.info("in EmailRepository.get with email id=" + emailId); + String fullKey = makeKey(emailId); + Map emailHash = stringRedisTemplate.opsForHash().entries(fullKey); + Email email = objectMapper.convertValue(emailHash, Email.class); + return (email); + } + // this is sample code demonstrating removing all the emails for a customer without using redisearch + public void delete(String emailId) { + log.info("in emailrepository.delete with emailId " + emailId); + String fullKey = makeKey(emailId); + stringRedisTemplate.delete(fullKey); + } + + public int deleteCustomerEmails (String customerId) { + log.info("in EmailRepository.deleteCustomerEmails with custid " + customerId); + String custEmailKey = "CustEmail" + ':' + customerId; + String fullEmailKey; + Set emailsToDelete = stringRedisTemplate.opsForSet().members(custEmailKey); + int emailCount = emailsToDelete.size(); + for (String emailKey : emailsToDelete) { + fullEmailKey = makeKey(emailKey); + log.info("emailKey to delete is " + fullEmailKey); + stringRedisTemplate.delete(fullEmailKey); + } + stringRedisTemplate.delete(custEmailKey); + return emailCount; + } + private String makeKey(String emailKey) { + return emailSearchIndexName + ':' + emailKey; + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/MerchantRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/MerchantRepository.java new file mode 100644 index 000000000..023a39bff --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/MerchantRepository.java @@ -0,0 +1,68 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Merchant; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import com.jphaugla.domain.Transaction; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; +@Slf4j +@Repository + +public class MerchantRepository{ + @Value("${app.merchantSearchIndexName}") + private String merchantSearchIndexName; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public MerchantRepository() { + + log.info("MerchantRepository constructor"); + } + + public String create(Merchant merchant) { + + Map merchantHash = objectMapper.convertValue(merchant, Map.class); + stringRedisTemplate.opsForHash().putAll(makeKey( merchant.getName()), merchantHash); + // redisTemplate.opsForHash().putAll("Merchant:" + merchant.getMerchantId(), merchantHash); + // logger.info(String.format("Merchant with ID %s saved", merchant.getName())); + return "Success\n"; + } + + public Merchant get(String merchantId) { + log.info("in MerchantRepository.get with merchant id=" + merchantId); + String fullKey = makeKey(merchantId); + Map merchantHash = stringRedisTemplate.opsForHash().entries(fullKey); + Merchant merchant = objectMapper.convertValue(merchantHash, Merchant.class); + return (merchant); + } + public String createAll(List merchantList) { + for (Merchant merchant : merchantList) { + create(merchant); + } + return "Success\n"; + } + + private String makeKey(String merchantId) { + return merchantSearchIndexName + ':' + merchantId; + } +} + diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/PhoneRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/PhoneRepository.java new file mode 100644 index 000000000..c300985f3 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/PhoneRepository.java @@ -0,0 +1,61 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Phone; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.util.Map; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; +@Repository + +public class PhoneRepository{ + @Value("${app.phoneSearchIndexName}") + private String phoneSearchIndexName; + + final Logger logger = LoggerFactory.getLogger(com.jphaugla.repository.PhoneRepository.class); + @Autowired + ObjectMapper objectMapper; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public PhoneRepository() { + + logger.info("PhoneRepository constructor"); + } + + public String create(Phone phone) { + + Map phoneHash = objectMapper.convertValue(phone, Map.class); + stringRedisTemplate.opsForHash().putAll(makeKey(phone.getPhoneNumber()), phoneHash); + // redisTemplate.opsForHash().putAll("Phone:" + phone.getPhoneId(), phoneHash); + // logger.info(String.format("Phone with ID %s saved", phone.getPhoneNumber())); + return "Success\n"; + } + + public Optional get(String phoneId) { + logger.info("in Phone Repository.get with phone id=" + phoneId); + String fullKey = makeKey(phoneId); + Map phoneHash = stringRedisTemplate.opsForHash().entries(fullKey); + logger.info("Full key is " + fullKey + " phoneHash is " + phoneHash); + Phone phone = objectMapper.convertValue(phoneHash, Phone.class); + logger.info("return phone " + phone.getPhoneNumber() + ":" + phone.getPhoneLabel() + ":" + phone.getCustomerId()); + return Optional.ofNullable((phone)); + } + + private String makeKey(String phoneId) { + return phoneSearchIndexName + ':' + phoneId; + } +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionRepository.java new file mode 100644 index 000000000..9b365f8a6 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionRepository.java @@ -0,0 +1,117 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Transaction; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + + +import java.time.Duration; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; +@Repository +@Slf4j +public class TransactionRepository{ + @Value("${app.transactionSearchIndexName}") + private String transactionSearchIndexName; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public TransactionRepository() { + + log.info("TransactionRepository constructor"); + } + + public String create(Transaction transaction) { + log.info("entering TransactionReposistory create transaction " + transaction.toString()); + if (transaction.getInitialdate() == null) { + long currentTimeMillis = System.currentTimeMillis(); + transaction.setInitialdate(Long.toString(currentTimeMillis)); + } + + Map transactionHash = objectMapper.convertValue(transaction, Map.class); + // remove null map values + while (transactionHash.values().remove(null)); + String fullKey = makeKey(transaction.getTranid()); + log.info("full key is " + fullKey); + stringRedisTemplate.opsForHash().putAll(fullKey, transactionHash); + // redisTemplate.opsForHash().putAll("Transaction:" + transaction.getTransactionId(), transactionHash); + // logger.info(String.format("Transaction with ID %s saved", transaction.getTranId())); + return fullKey; + } + + public String create (Transaction transaction, Boolean doExpire) { + String returnKey = create(transaction); + stringRedisTemplate.expire(returnKey, Duration.ofDays(2)); + return returnKey; + } + + public String createAll(List transactionList) { + for (Transaction transaction : transactionList) { + create(transaction); + } + return "Success\n"; + } + + public Transaction get(String tranId) { + log.info("in TransactionRepository.get with transaction id=" + tranId); + String fullKey = makeKey(tranId); + Map transactionHash = stringRedisTemplate.opsForHash().entries(fullKey); + Transaction transaction = objectMapper.convertValue(transactionHash, Transaction.class); + return (transaction); + } + + public String getAmount(String tranId) { + log.info("in TransactionRepository.getAmount with transaction id=" + tranId); + String fullKey = makeKey(tranId); + String amount = (String) stringRedisTemplate.opsForHash().get(fullKey, "amount"); + return amount; + } + public void updateStatus(String tranId, String targetStatus, String timeString) { + stringRedisTemplate.opsForHash().put(makeKey(tranId), + "status", targetStatus); + if (targetStatus.equals("POSTED")) { + updateDate(tranId, "postingDate", timeString); + } else { + updateDate(tranId, "settlementDate", timeString); + } + } + + public void updateDate(String tranId, String dateField, String timeString) { + stringRedisTemplate.opsForHash().put(makeKey(tranId), dateField, + timeString); + } + + public void addTags(String tranId, String tagDelimitedString) { + stringRedisTemplate.opsForHash().put(makeKey(tranId), "transactionTags", + tagDelimitedString); + } + public String getTags(String tranId) { + log.info("in getTransactionTagList with transactionID=" + tranId); + // hold set of transactions for a tag on an account + String transactionKey = makeKey(tranId); + String existingTags = (String) stringRedisTemplate.opsForHash().get(transactionKey, + "transactionTags"); + return existingTags; + } + + public void addDispute(String tranId, String disputeId) { + String transactionKey = makeKey(tranId); + stringRedisTemplate.opsForHash().put(transactionKey, "disputeid", disputeId); + + } + public String makeKey(String tranId) { + return transactionSearchIndexName + ":" + tranId; + } +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionReturnRepository.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionReturnRepository.java new file mode 100644 index 000000000..dc20d7d57 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/repository/TransactionReturnRepository.java @@ -0,0 +1,67 @@ +package com.jphaugla.repository; + +import com.jphaugla.domain.Transaction; +import com.jphaugla.domain.TransactionReturn; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Repository; +@Slf4j +@Repository + +public class TransactionReturnRepository{ + + @Autowired + ObjectMapper objectMapper; + + @Value("${app.transactionReturnSearchIndexName}") + private String transactionReturnSearchIndexName; + + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public TransactionReturnRepository() { + + log.info("TransactionReturnRepository constructor"); + } + + public String create(TransactionReturn transactionReturn) { + Map transactionReturnHash = objectMapper.convertValue(transactionReturn, Map.class); + stringRedisTemplate.opsForHash().putAll(makeKey(transactionReturn.getReasonCode()), transactionReturnHash); + // redisTemplate.opsForHash().putAll("TransactionReturn:" + transactionReturn.getTransactionReturnId(), transactionReturnHash); + log.info(String.format("TransactionReturn with ID %s saved", transactionReturn.getReasonCode())); + return "Success\n"; + } + public String createAll(List transactionReturnList) { + for (TransactionReturn transactionReturn : transactionReturnList) { + create(transactionReturn); + } + return "Success\n"; + } + + public TransactionReturn get(String transactionReturnId) { + log.info("in TransactionReturnRepository.get with transactionReturn id=" + transactionReturnId); + String fullKey = makeKey(transactionReturnId); + Map transactionReturnHash = stringRedisTemplate.opsForHash().entries(fullKey); + TransactionReturn transactionReturn = objectMapper.convertValue(transactionReturnHash, TransactionReturn.class); + return (transactionReturn); + } + private String makeKey(String transactionReturnId) { + return transactionReturnSearchIndexName + ':' + transactionReturnId; + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/AsyncService.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/AsyncService.java new file mode 100644 index 000000000..9977c78d4 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/AsyncService.java @@ -0,0 +1,71 @@ +package com.jphaugla.service; + +import com.jphaugla.domain.*; +import com.jphaugla.repository.*; +import org.springframework.beans.factory.annotation.Autowired; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + + +@Service +public class AsyncService { + + @Autowired + private AccountRepository accountRepository; + @Autowired + private CustomerRepository customerRepository; + @Autowired + private TransactionRepository transactionRepository; + @Autowired + private PhoneRepository phoneRepository; + @Autowired + private EmailRepository emailRepository; + + @Async("threadPoolTaskExecutor") + public CompletableFuture writeAllTransaction(List transactions) { + transactionRepository.createAll(transactions); + return CompletableFuture.completedFuture(0); + } + @Async("threadPoolTaskExecutor") + public CompletableFuture writeTransaction(Transaction transaction) { + transactionRepository.create(transaction); + return CompletableFuture.completedFuture(0); + } + + @Async("threadPoolTaskExecutor") + public CompletableFuture writeAllAccounts(List accounts){ + // Integer count = accounts.size(); + accountRepository.createAll(accounts); + return CompletableFuture.completedFuture(0); + } + + @Async("threadPoolTaskExecutor") + public CompletableFuture writeAccounts(Account account){ + // Integer count = accounts.size(); + accountRepository.create(account); + return CompletableFuture.completedFuture(0); + } + + @Async("threadPoolTaskExecutor") + public CompletableFuture writeCustomer(Customer customer) { + customerRepository.create(customer); + return CompletableFuture.completedFuture(0); + } + + @Async("threadPoolTaskExecutor") + public CompletableFuture writePhone(Phone phoneNumber) { + phoneRepository.create(phoneNumber); + return CompletableFuture.completedFuture(0); + } + + @Async("threadPoolTaskExecutor") + public CompletableFuture writeEmail(Email email) { + emailRepository.create(email); + return CompletableFuture.completedFuture(0); + } + +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/BankService.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/BankService.java new file mode 100644 index 000000000..e5b3e9f5e --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/BankService.java @@ -0,0 +1,822 @@ +package com.jphaugla.service; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicLong; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jphaugla.data.BankGenerator; +import com.jphaugla.domain.*; +import com.jphaugla.repository.*; + +import io.lettuce.core.RedisCommandExecutionException; + +import lombok.extern.slf4j.Slf4j; +import org.joda.time.DateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.core.env.Environment; + +import org.springframework.data.redis.core.StringRedisTemplate; + +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Service; +import redis.clients.jedis.ConnectionPoolConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisPooled; +import redis.clients.jedis.UnifiedJedis; +import redis.clients.jedis.search.Document; +import redis.clients.jedis.search.Query; +import redis.clients.jedis.search.SearchResult; +import redis.clients.jedis.search.aggr.AggregationBuilder; +import redis.clients.jedis.search.aggr.AggregationResult; +import redis.clients.jedis.search.aggr.Reducers; + + +@Service +@Slf4j + +public class BankService { + + private static BankService bankService = new BankService(); + @Autowired + private AsyncService asyncService; + @Autowired + private TopicProducer topicProducer; + @Autowired + private CassandraTransRepository cassandraTransRepository; + @Autowired + private AccountRepository accountRepository; + @Autowired + private PhoneRepository phoneRepository; + @Autowired + private EmailRepository emailRepository; + @Autowired + private MerchantRepository merchantRepository; + @Autowired + private TransactionReturnRepository transactionReturnRepository; + @Autowired + private TransactionRepository transactionRepository; + @Autowired + private DisputeRepository disputeRepository; + @Autowired + private CustomerRepository customerRepository; + @Autowired + private StringRedisTemplate redisTemplate; + @Autowired + ObjectMapper objectMapper; + + + @Value("${app.transactionSearchIndexName}") + private String transactionSearchIndexName; + @Value("${app.transactionReturnSearchIndexName}") + private String transactionReturnSearchIndexName; + @Value("${app.customerSearchIndexName}") + private String customerSearchIndexName; + @Value("${app.merchantSearchIndexName}") + private String merchantSearchIndexName; + @Value("${app.accountSearchIndexName}") + private String accountSearchIndexName; + @Value("${app.disputeSearchIndexName}") + private String disputeSearchIndexName; + + private long timerSum = 0; + private AtomicLong timerCount = new AtomicLong(); + @Autowired + private Environment env; + + UnifiedJedis client; + + public static BankService getInstance() { + return bankService; + } + // + // Customer + // + public Optional getCustomer(String customerId) { + log.info("in bankservice.getCustomer with ID " + customerId); + Customer returnCustomer = customerRepository.get(customerId); + log.info("returned customer " + returnCustomer); + return Optional.of(returnCustomer); + } + + + public void saveSampleCustomer() throws ParseException, RedisCommandExecutionException { + Date create_date = new SimpleDateFormat("yyyy-MM-dd").parse("2020-03-28"); + Date last_update = new SimpleDateFormat("yyyy-MM-dd").parse("2020-03-29"); + String cust = "cust0001"; + Email home_email = new Email("jasonhaugland@gmail.com", "home", cust); + Email work_email = new Email("jason.haugland@redislabs.com", "work", cust); + Phone cell_phone = new Phone("612-408-4394", "cell", cust); + emailRepository.create(home_email); + emailRepository.create(work_email); + phoneRepository.create(cell_phone); + Customer customer = new Customer(cust, "4744 17th av s", "", + "Home", "N", "Minneapolis", "00", + "jph", Long.toString(create_date.getTime()), "IDR", + "A", "BANK", "1949.01.23", + "Ralph", "Ralph Waldo Emerson", "M", + "887778989", "SSN", "Emerson", Long.toString(last_update.getTime()), + "jph", "Waldo", "MR", + "help", "MN", "55444", "55444-3322" + ); + customerRepository.create(customer); + } + + public void postCustomer(Customer customer) { + log.info("in postCustomer with Customer =" + customer); + customerRepository.create(customer); + Email home_email = new Email(customer.getCustomerId() + "@gmail.com", "home", customer.getCustomerId()); + Email work_email = new Email(customer.getCustomerId() + "@redislabs.com", "work", customer.getCustomerId()); + Phone cell_phone = new Phone("612-408-4394", "cell", customer.getCustomerId()); + emailRepository.create(home_email); + emailRepository.create(work_email); + phoneRepository.create(cell_phone); + } + + public SearchResult search(String indexName, String queryString, int offset, int limit, String sortBy, boolean ascending) { + // Let's put all the informations in a Map top make it easier to return JSON object + // no need to have "predefine mapping" + client = jedis_connection(); + Map returnValue = new HashMap<>(); + Map resultMeta = new HashMap<>(); + log.info("starting search with querystring" + queryString); + // Create a simple query + Query query = new Query(queryString) + .setWithScores() + .limit(offset, limit); + // if sort by parameter add it to the query + if (sortBy != null && !sortBy.isEmpty()) { + query.setSortBy(sortBy, ascending); // Ascending by default + } + + // Execute the query + + return client.ftSearch(indexName, query); + } + + + public SearchResult search(String indexName, String queryString) { + return search(indexName, queryString, 0, 10, null, true); + } + + + public int deleteCustomer(String customerString) { + // List customerIDList = customerRepository.findByStateAbbreviationAndCity(state, city); + // client = jedis_connection(); + String queryString = buildTagQuery("customerId", customerString); + log.info("query string is " + queryString); + int returnValue = 0; + SearchResult results = search(customerSearchIndexName, queryString); + List docs = results.getDocuments(); + for (Document document : docs) { + String fullKey = (String) document.getId(); + redisTemplate.delete(fullKey); + returnValue++; + // logger.warn("adding to transaction list string=" + onlyID + " fullKey is " + fullKey) + } + return (returnValue); + } + + public SearchResult getCustomerByStateCity(String state, String city) { + + // List customerIDList = customerRepository.findByStateAbbreviationAndCity(state, city); + String stateQuery = buildTagQuery("stateAbbreviation", state); + String cityQuery = buildTagQuery("city", city); + String queryString = stateQuery + " " + cityQuery; + log.info("query string is " + queryString); + return search(customerSearchIndexName, queryString); + } + + public SearchResult getCustomerIdsbyZipcodeLastname(String zipcode, String lastName) { + String zipString = buildTagQuery("zipcode", zipcode); + String lastNameStaring = buildTagQuery("lastName", lastName); + String queryString = zipString + " " + lastNameStaring; + return search(customerSearchIndexName, queryString); + } + + // + // Phone + // + public Optional getPhoneNumber(String phoneString) { + return phoneRepository.get(phoneString); + } + + public Customer getCustomerByPhone(String phoneString) { + // get list of customers having this phone number + // first, get phone hash with this phone number + // next, get the customer id with this phone number + // third, use the customer id to get the customer + Optional optPhone = getPhoneNumber(phoneString); + Optional returnCustomer = null; + Customer returnCust = null; + log.info("in bankservice.getCustomerByPhone optphone is" + optPhone.isPresent()); + if (optPhone.isPresent()) { + Phone onePhone = optPhone.get(); + String customerId = onePhone.getCustomerId(); + log.info(" onePhone is " + onePhone.getPhoneNumber() + ":" + onePhone.getPhoneLabel() + ":" + onePhone.getCustomerId()); + returnCustomer = Optional.ofNullable(customerRepository.get(customerId)); + } + + if ((returnCustomer != null) && (returnCustomer.isPresent())) { + returnCust = returnCustomer.get(); + // log.info("customer is " + returnCust); + + } + return returnCust; + } + + // + // Email + // + public Optional getEmail(String email) { + return Optional.ofNullable(emailRepository.get(email)); + } + + public Customer getCustomerByEmail(String emailString) { + // get list of customers having this email number + // first, get email hash with this email number + // next, get the customer id with this email number + // third, use the customer id to get the customer + Optional optionalEmail = getEmail(emailString); + Optional returnCustomer = Optional.empty(); + Customer returnCust = null; + log.info("in bankservice.getCustomerByEmail optEmail is" + optionalEmail.isPresent()); + if (optionalEmail.isPresent()) { + Email oneEmail = optionalEmail.get(); + String customerId = oneEmail.getCustomerId(); + // log.info("customer is " + customerId); + returnCustomer = Optional.ofNullable(customerRepository.get(customerId)); + } + + if ((returnCustomer.isPresent())) { + returnCust = returnCustomer.get(); + log.info("customer is " + returnCust); + + } + return returnCust; + } + + public int deleteCustomerEmail(String customerID) { + log.info("in bankservice.deleteCustomerEmail with CustomerID " + customerID); + return emailRepository.deleteCustomerEmails(customerID); + } + + // + // Utility methods + // + private void sleep(int i) { + try { + Thread.sleep(i); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public String getDateFullDayQueryString(String stringDate) throws ParseException { + Date inDate = new SimpleDateFormat("MM/dd/yyyy").parse(stringDate); + long inUnix = inDate.getTime(); + // since the transaction ID is also in the query can take a larger reach around the date column + long startUnix = inUnix - 86400 * 1000; + long endUnix = inUnix + 86400 * 1000; + return " @postingDate:[" + startUnix + " " + endUnix + "]"; + } + + public String getDateToFromQueryString(Date startDate, Date endDate) throws ParseException { + + long startUnix = startDate.getTime(); + long endUnix = endDate.getTime(); + return " @postingDate:[" + startUnix + " " + endUnix + "]"; + } + + // + // Transaction + // + + public Transaction getTransaction(String transactionID) { + + Transaction returnTransaction = transactionRepository.get(transactionID); + if ((returnTransaction != null) && (returnTransaction.getTranid() != null) ) { + log.info("found transaction in redis"); + } else { + log.info("transaction not found in redis, looking in cassandra"); + Optional optionalTransaction = cassandraTransRepository.findById(transactionID); + if (optionalTransaction.isPresent()) { + Transaction cassandraTransaction = optionalTransaction.get(); + if (cassandraTransaction.getTranid() != null) { + log.info("cassandra has the data "); + // returnTransaction = cassandraTransactionCopytoTransaction(cassandraTransaction); + // write it back to redis + returnTransaction = cassandraTransaction; + writeTransaction(cassandraTransaction, true); + } + } + } + if ((returnTransaction != null) && (returnTransaction.getTranid() != null) ) + return returnTransaction; + else { + log.info("cassandra doesn't have it either"); + return null; + } + } +/* + + private Transaction cassandraTransactionCopytoTransaction(CassandraTransaction cassandraTransaction) { + Transaction returnTransaction= new Transaction(); + returnTransaction.setTranid(cassandraTransaction.getTranid()); + returnTransaction.setAmount(cassandraTransaction.getAmount()); + returnTransaction.setDescription(cassandraTransaction.getDescription()); + returnTransaction.setLocation(cassandraTransaction.getLocation()); + returnTransaction.setTransactionTags(cassandraTransaction.getTransactiontags()); + returnTransaction.setAccountno(cassandraTransaction.getAccountno()); + returnTransaction.setAmounttype(cassandraTransaction.getAmounttype()); + returnTransaction.setDisputeId(cassandraTransaction.getDisputeid()); + returnTransaction.setInitialDate(cassandraTransaction.getInitialdate()); + returnTransaction.setMerchant(cassandraTransaction.getMerchant()); + returnTransaction.setOriginalamount(cassandraTransaction.getOriginalamount()); + returnTransaction.setPostingDate(cassandraTransaction.getPostingdate()); + returnTransaction.setReferencekeytype(cassandraTransaction.getReferencekeytype()); + returnTransaction.setReferencekeyvalue(cassandraTransaction.getReferencekeyValue()); + returnTransaction.setSettlementDate(cassandraTransaction.getSettlementdate()); + returnTransaction.setStatus(cassandraTransaction.getStatus()); + returnTransaction.setTransactionReturn(cassandraTransaction.getTransactionreturn()); + returnTransaction.setTrancd(cassandraTransaction.getTrancd()); + return returnTransaction; + } +*/ + + private List getTransactionByStatus(String transactionStatus) throws ExecutionException, InterruptedException { + String queryString = buildTagQuery("status", transactionStatus); + SearchResult results = search(transactionSearchIndexName, queryString, 0, 10000, null, true); + // this code snippet get converts results to List of Transaction IDs + List transIdList = new ArrayList(); + List docs = results.getDocuments(); + + for (Document document : docs) { + String fullKey = (String) document.getId(); + String onlyID = fullKey.replace(transactionSearchIndexName + ':', ""); + transIdList.add(onlyID); + // logger.warn("adding to transaction list string=" + onlyID + " fullKey is " + fullKey); + } + return transIdList; + } + + public void transactionStatusChange(String targetStatus) throws IllegalAccessException, ExecutionException, InterruptedException { + // move target from authorized->settled->posted + log.info("transactionStatusChange targetStatus is " + targetStatus); + CompletableFuture transaction_cntr = null; + List transIdList = new ArrayList(); + long unixTime = System.currentTimeMillis(); + String stringUnixTime = String.valueOf(unixTime); + if (targetStatus.equals("POSTED")) { + transIdList = getTransactionByStatus("SETTLED"); + } else { + transIdList = getTransactionByStatus("AUTHORIZED"); + } + log.info("number of transactions " + transIdList.size()); + + for (String tranID : transIdList) { + transactionRepository.updateStatus(tranID, targetStatus, stringUnixTime); + } + log.info("Finished updating " + transIdList.size()); + } + + + // writeTransaction using crud without future + private void writeTransaction(Transaction transaction, boolean doExpire) { + // log.info("writing a transaction " + transaction); + transactionRepository.create(transaction, doExpire); + } + + // writeTransaction using crud with Future + private CompletableFuture writeTransactionFuture(Transaction transaction) throws IllegalAccessException { + + CompletableFuture transaction_cntr = null; + transaction_cntr = asyncService.writeTransaction(transaction); + // writes a sorted set to be used as the posted date index + + return transaction_cntr; + } + + public List> transactionStatusReport() { + client = jedis_connection(); + // AggregateResults aggregateResults = commands.ftAggregate((transactionSearchIndexName, "*", + // AggregateOptions.builder().load("status").operation(MRangeOptions.GroupBy.properties("status").reducer(Reducers.Count.as("COUNT")).build()).build()); + AggregationBuilder aggregation = new AggregationBuilder() + .groupBy("@status", Reducers.count().as("COUNT")); + log.info("aggregation is" + aggregation.toString()); + AggregationResult aggrResult = client.ftAggregate(transactionSearchIndexName, aggregation); + int resultSize = aggrResult.getResults().size(); + log.info("result size is " + resultSize); + log.info(aggrResult.getResults().toString()); + List> docsToReturn = new ArrayList<>(); + + // AggregateOptions groupByOptions = AggregateOptions.operation(Group.by("status").reducer(Reducers.Count.as("COUNT")).build()).build(); + // AggregateResults aggregateResults = commands.ftAggregate(transactionSearchIndexName, "*", groupByOptions); + return (aggrResult.getResults()); + } + + public void saveSampleTransaction(Boolean doKafka) throws ParseException, RedisCommandExecutionException, JsonProcessingException { + Date settle_date = new SimpleDateFormat("yyyy/MM/dd").parse("2021/07/28"); + Date post_date = new SimpleDateFormat("yyyy/MM/dd").parse("2021/07/28"); + Date init_date = new SimpleDateFormat("yyyy/MM/dd").parse("2021/07/27"); + + Merchant merchant = new Merchant("Cub Foods", "5411", + "Grocery Stores", "MN", "US"); + log.info("before save merchant"); + merchantRepository.create(merchant); + + Transaction transaction = new Transaction("1234","acct01", + "Debit", merchant.getName() + ":" + "acct01", "referenceKeyType", + "referenceKeyValue", "323.23", "323.22", "1631", + "Test Transaction", Long.toString(init_date.getTime()), Long.toString(settle_date.getTime()), + Long.toString(post_date.getTime()), "POSTED", null, null, "ATM665", "Outdoor"); + log.info("before save transaction"); + if (doKafka) { + writeTransactionKafka(transaction); + } else { + writeTransaction(transaction, false); + } + } + + public void addTag(String transactionID, String tag, String operation) { + log.info("in addTag with transID=" + transactionID + " and tag " + tag); + // hold set of transactions for a tag on an account + HashSet tagHash = getTransactionTagList(transactionID); + + if (operation.equals("ADD")) { + tagHash.add(tag); + } else { + tagHash.remove(tag); + } + String tagDelimitedString = String.join(":", tagHash); + transactionRepository.addTags(transactionID, tagDelimitedString); + + } + + public HashSet getTransactionTagList(String transactionID) { + log.info("in getTransactionTagList with transactionID=" + transactionID); + // hold set of transactions for a tag on an account + String existingTags = transactionRepository.getTags(transactionID); + HashSet tagHash = new HashSet(); + if (existingTags != null) { + String[] tagArray = existingTags.split(":"); + List tagList = Arrays.asList(tagArray); + tagHash = new HashSet(tagList); + } + return tagHash; + } + + + public SearchResult getTaggedTransactions(String accountNo, String tag) { + log.info("in getTaggedTransactions with accountNo=" + accountNo + " and tag " + tag); + String accountNoString = buildTagQuery("accountNo", accountNo); + String tranTagString = buildTagQuery("transactionTags", tag); + String queryString = accountNoString + " " + tranTagString; + log.info("query is " + queryString); + + return search(transactionSearchIndexName, queryString); + } + + /* + public String testPipeline(Integer noOfRecords) { + BankGenerator.Timer pipelineTimer = new BankGenerator.Timer(); + this.redisTemplate.executePipelined(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) + throws DataAccessException { + connection.openPipeline(); + String keyAndValue=null; + for (int index=0;index accounts = createCustomerAccount(noOfCustomers, key_suffix); + log.info("after accounts"); + BankGenerator.date = new DateTime().minusDays(noOfDays).withTimeAtStartOfDay(); + BankGenerator.Timer transTimer = new BankGenerator.Timer(); + + int totalTransactions = noOfTransactions * noOfDays; + + log.info("Writing " + totalTransactions + " transactions for " + noOfCustomers + + " customers. suffix is " + key_suffix); + int account_size = accounts.size(); + int transactionsPerAccount = noOfDays * noOfTransactions / account_size; + log.info("number of accounts generated is " + account_size + " transactionsPerAccount " + + transactionsPerAccount); + List merchants = BankGenerator.createMerchantList(); + List transactionReturns = BankGenerator.createTransactionReturnList(); + merchantRepository.createAll(merchants); + log.info("completed merchant next is transactionReturn"); + transactionReturnRepository.createAll(transactionReturns); + CompletableFuture> kafka_cntr = null; + CompletableFuture transaction_cntr = null; + int transactionIndex = 0; + List transactionList = new ArrayList<>(); + for (Account account : accounts) { + log.info("writing account " + account.getAccountNo()); + for (int i = 0; i < transactionsPerAccount; i++) { + transactionIndex++; + Transaction randomTransaction = BankGenerator.createRandomTransaction(noOfDays, transactionIndex, account, key_suffix, + merchants, transactionReturns); + if (doKafka) + writeTransactionKafka(randomTransaction); + else + transaction_cntr = writeTransactionFuture(randomTransaction); + } + } + if (!doKafka) { + transaction_cntr.get(); + } + transTimer.end(); + log.info("Finished writing " + totalTransactions + " created in " + + transTimer.getTimeTakenSeconds() + " seconds."); + } + + private void writeTransactionKafka(Transaction randomTransaction) throws JsonProcessingException { + try { + String jsonStr = objectMapper.writeValueAsString(randomTransaction); + String key = randomTransaction.getTranid(); + topicProducer.send(jsonStr, randomTransaction.getTranid()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + } + + ; + + // + // Account + // + public void saveSampleAccount() throws ParseException, RedisCommandExecutionException { + Date create_date = new SimpleDateFormat("yyyy/MM/dd").parse("2010/03/28"); + log.info("saveSampleAccount with create_date " + create_date.getTime()); + Account account = new Account("cust001", "acct001", + "credit", "teller", "active", + "ccnumber666655", Long.toString(create_date.getTime()), + null, null, "jason", null); + accountRepository.create(account); + } + + ; + + public SearchResult getAccountTransactions(String account, Date startDate, Date endDate) + throws ParseException, RedisCommandExecutionException { + log.info("in getAccountTransactions account is " + account); + log.info("startdate is " + startDate + " endDate is" + endDate); + String tofromQuery = getDateToFromQueryString(startDate, endDate); + String accountString = buildTagQuery("accountNo", account); + String queryString = accountString + " " + tofromQuery; + log.info("query is " + queryString); + + return search(transactionSearchIndexName, queryString); + } + + ; + + public SearchResult getCreditCardTransactions(String creditCard, Date startDate, Date endDate) + throws ParseException, RedisCommandExecutionException { + log.info("credit card is " + creditCard + " start is " + startDate + " end is " + endDate); + + SearchResult transactionResults = null; + String queryString = buildTagQuery("cardNum", creditCard); + SearchResult accountResults = search(accountSearchIndexName, queryString); + List docs = accountResults.getDocuments(); + // result set has all accounts with a credit card + // build a query to match any of these merchants + if (docs != null) { + int i = 0; + String accountListQueryString = "@accountNo:"; + for (Document document : docs) { + if (i > 0) accountListQueryString = accountListQueryString + "|"; + String accountNo = (String) document.getId(); + String onlyID = accountNo.replace(accountSearchIndexName + ':', ""); + accountListQueryString = accountListQueryString + "{" + onlyID + "}"; + i += 1; + } + accountListQueryString = accountListQueryString; + log.info("accountListQueryString is " + accountListQueryString); + String tofromQuery = getDateToFromQueryString(startDate, endDate); + queryString = accountListQueryString + tofromQuery; + log.info("queryString is " + queryString); + transactionResults = search(transactionSearchIndexName, queryString); + } + return transactionResults; + } + + ; + + + private List createCustomerAccount(int noOfCustomers, String key_suffix) throws ExecutionException, InterruptedException, RedisCommandExecutionException { + + log.info("Creating " + noOfCustomers + " customers with accounts and suffix " + key_suffix); + BankGenerator.Timer custTimer = new BankGenerator.Timer(); + List accounts = null; + List allAccounts = new ArrayList<>(); + List emails = null; + List phoneNumbers = null; + CompletableFuture account_cntr = null; + CompletableFuture customer_cntr = null; + CompletableFuture email_cntr = null; + CompletableFuture phone_cntr = null; + int totalAccounts = 0; + int totalEmails = 0; + int totalPhone = 0; + log.info("before the big for loop"); + for (int i = 0; i < noOfCustomers; i++) { + // log.info("int noOfCustomer for loop i=" + i); + Customer customer = BankGenerator.createRandomCustomer(key_suffix); + List emailList = BankGenerator.createEmail(customer.getCustomerId()); + List phoneList = BankGenerator.createPhone(customer.getCustomerId()); + for (Phone phoneNumber : phoneNumbers = phoneList) { + phone_cntr = asyncService.writePhone(phoneNumber); + } + totalPhone = totalPhone + phoneNumbers.size(); + for (Email email : emails = emailList) { + email_cntr = asyncService.writeEmail(email); + } + totalEmails = totalEmails + emails.size(); + accounts = BankGenerator.createRandomAccountsForCustomer(customer, key_suffix); + totalAccounts = totalAccounts + accounts.size(); + for (Account account : accounts) { + account_cntr = asyncService.writeAccounts(account); + } + customer_cntr = asyncService.writeCustomer(customer); + if (!accounts.isEmpty()) { + allAccounts.addAll(accounts); + } + } + // log.info("before the gets"); + assert account_cntr != null; + account_cntr.get(); + assert customer_cntr != null; + customer_cntr.get(); + assert email_cntr != null; + email_cntr.get(); + assert phone_cntr != null; + phone_cntr.get(); + custTimer.end(); + log.info("Customers=" + noOfCustomers + " Accounts=" + totalAccounts + + " Emails=" + totalEmails + " Phones=" + totalPhone + " in " + + custTimer.getTimeTakenSeconds() + " secs"); + return allAccounts; + } + + // + // TransactionReturns + // + + public SearchResult getTransactionReturns() { + log.info("in getTransactionReturns "); + String queryString = "*"; + + return search(transactionReturnSearchIndexName, queryString); + } + + // + // Merchant + // + public SearchResult getMerchantCategoryTransactions(String in_merchantCategory, String account, + Date startDate, Date endDate) throws ParseException, RedisCommandExecutionException { + String queryString = buildTagQuery("categoryCode", in_merchantCategory); + SearchResult merchantResults = search(merchantSearchIndexName, queryString); + SearchResult transactionResults = null; + List docs = merchantResults.getDocuments(); + // result set has all merchants with a category code + // build a query to match any of these merchants + if (docs != null) { + int i = 0; + StringBuilder merchantListQueryString = new StringBuilder("@merchant:{"); + for (Document document : docs) { + if (i > 0) merchantListQueryString.append("|"); + String merchantKey = (String) document.getId(); + log.info(merchantKey); + String onlyID = merchantKey.replace(merchantSearchIndexName + ':', ""); + log.info(onlyID); + merchantListQueryString.append(onlyID); + i += 1; + } + merchantListQueryString = new StringBuilder(merchantListQueryString.append("}").toString()); + log.info("merchantListQueryString is " + merchantListQueryString); + String tofromQuery = getDateToFromQueryString(startDate, endDate); + String accountString = buildTagQuery("accountNo", account); + queryString = accountString + " " + merchantListQueryString + tofromQuery; + log.info("queryString is " + queryString); + transactionResults = search(transactionSearchIndexName, queryString); + } + return transactionResults; + } + + public SearchResult getMerchantTransactions(String in_merchant, String account, Date startDate, Date endDate) + throws ParseException, RedisCommandExecutionException { + log.info("in getMerchantTransactions merchant is " + in_merchant + " and account is " + account); + log.info("startdate is " + startDate + " endDate is" + endDate); + String tofromQuery = getDateToFromQueryString(startDate, endDate); + String merchantString = buildTagQuery("merchant", in_merchant); + String accountString = buildTagQuery("accountNo", account); + String queryString = merchantString + " " + accountString + " " + tofromQuery; + log.info("query is " + queryString); + + return search(transactionSearchIndexName, queryString); + } + + ; + + private UnifiedJedis jedis_connection() { + // Get the configuration from the application properties/environment + UnifiedJedis unifiedJedis; + String redisHost = "localhost"; // default name + int redisPort = 6379; + String redisPassword = ""; + + redisHost = env.getProperty("redis.host", "localhost"); + redisPort = Integer.parseInt(env.getProperty("redis.port", "6379")); + redisPassword = env.getProperty("spring.redis.password", ""); + + ConnectionPoolConfig poolConfig = new ConnectionPoolConfig(); + poolConfig.setMaxIdle(50); + poolConfig.setMaxTotal(50); + HostAndPort hostAndPort = new HostAndPort(redisHost, redisPort); + + log.info("Host: " + redisHost + " Port " + String.valueOf(redisPort)); + if (!(redisPassword.isEmpty())) { + String redisURL = "redis://:" + redisPassword + '@' + redisHost + ':' + String.valueOf(redisPort); + log.info("redisURL is " + redisURL); + unifiedJedis = new JedisPooled(redisURL); + } else { + log.info(" no password"); + unifiedJedis = new JedisPooled(hostAndPort); + } + return unifiedJedis; + } + + private String buildTagQuery(String fieldName, String fieldValue) { + return ("@" + fieldName + ":{" + fieldValue + "}"); + } + + + public void postDispute(Dispute dispute) throws ParseException { + log.info("in bs.postDispute with Dispute =" + dispute); + long unixTime = System.currentTimeMillis(); + + String stringUnixTime = String.valueOf(unixTime); + // incoming is only a date and not a timestampe, change to a timestamp + Date use_date = new SimpleDateFormat("yyyy/MM/dd").parse(dispute.getFilingDate()); + String filingDateTime = Long.toString(use_date.getTime()); + dispute.setFilingDate(filingDateTime); + dispute.setLastUpdateDate(String.valueOf(stringUnixTime)); + Transaction transaction = transactionRepository.get(dispute.getTranId()); + dispute.setChargeBackAmount(transaction.getAmount()); + log.info("before create with Dispute =" + dispute); + disputeRepository.create(dispute); + transactionRepository.addDispute(dispute.getTranId(),dispute.getDisputeId()); + } + + public void putDisputeChargeBackReason(String disputeId, String reasonCode) { + + + disputeRepository.setChargeBackReason(disputeId, reasonCode ); + } + + + public void acceptDisputeChargeBack(String disputeId) { + disputeRepository.acceptChargeBack(disputeId); + } + + public void resolvedDispute(String disputeId) { + disputeRepository.resolved(disputeId); + } + + public Dispute getDispute(String disputeId) { + return disputeRepository.get(disputeId); + } + + public SearchResult mostRecentTransactions(String account) { + log.info("in bs.mostrecentTransactions with account=" + account); + String accountString = buildTagQuery("accountNo", account); + return search(transactionSearchIndexName, accountString, 0, 20, "postingDate", + false); + } +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/TopicProducer.java b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/TopicProducer.java new file mode 100644 index 000000000..7af4c922d --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/java/com/jphaugla/service/TopicProducer.java @@ -0,0 +1,36 @@ +package com.jphaugla.service; + +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Service; + +import java.util.concurrent.CompletableFuture; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TopicProducer { + private static final Logger logger = LoggerFactory.getLogger(TopicProducer.class); + + @Value("${topic.name.producer}") + private String topicName; + + private final KafkaTemplate kafkaTemplate; + + public void send(String message, String key) { + CompletableFuture> future = kafkaTemplate.send(topicName, key, message); + future.whenComplete((result, ex) -> { + if (ex == null) { + // logger.info("Sent message=[" + message + "] with offset=[" + result.getRecordMetadata().offset() + "]"); + } else { + logger.info("Unable to send message=[" + + message + "] due to : " + ex.getMessage()); + } + }); + } +} diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/application.properties b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/application.properties new file mode 100644 index 000000000..7a2d3eb66 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/application.properties @@ -0,0 +1,44 @@ +spring.redis.host=${REDIS_HOST} +spring.redis.port=${REDIS_PORT} +spring.redis.password=${REDIS_PASSWORD} +spring.redis.ssl=false +spring.redis.timeout=1000ms +spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration + +# Producer properties +spring.kafka.producer.bootstrap-servers=${KAFKA_HOST}:${KAFKA_PORT} +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.group-id=group_id +topic.name.producer=transactions + +spring.data.cassandra.keyspace-name=banking +spring.data.cassandra.contact-points=${SPRING_CASSANDRA_HOST} +spring.data.cassandra.port=${SPRING_CASSANDRA_PORT} +# spring.data.cassandra.username=${SPRING_CASSANDRA_USER} +# spring.data.cassandra.password=${SPRING_CASSANDRA_PASSWORD} +spring.data.cassandra.cluster_name=${SPRING_CASSANDRA_CLUSTER} +spring.data.cassandra.local-datacenter=${SPRING_CASSANDRA_DATACENTER} + + +# Common Kafka Properties +auto.create.topics.enable=true +app.numberOfRatings=5000 +app.ratingStars=5 +app.numberOfCarts=2500 +app.transactionSearchIndexName=Trans +app.customerSearchIndexName=Cust +app.merchantSearchIndexName=Merch +app.accountSearchIndexName=Acct +app.emailSearchIndexName=Eml +app.phoneSearchIndexName=Phne +app.transactionReturnSearchIndexName=TransRet +app.disputeSearchIndexName=Disp +logging.level.org.springframework=INFO +logging.level.com.jphaugla=DEBUG +logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n +#server.ssl.key-store=./src/main/resources/ssl/client-keystore.p12 +#server.ssl.key-store-password=${KEYSTORE_PASSWORD} +#server.ssl.trust-store=./src/main/resources/ssl/client-truststore.p12 +#server.ssl.trust-store-password=${TRUSTSTORE_PASSWORD} + diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatekeystore.sh b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatekeystore.sh new file mode 100644 index 000000000..9e4bdc8f1 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatekeystore.sh @@ -0,0 +1,5 @@ +openssl pkcs12 -export \ + -in ./client_cert_app_001.pem \ + -inkey ./client_key_app_001.pem \ + -out client-keystore.p12 \ + -name "APP_01_P12" diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatepems.sh b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatepems.sh new file mode 100644 index 000000000..f7f975da8 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatepems.sh @@ -0,0 +1,7 @@ +openssl req \ + -nodes \ + -newkey rsa:2048 \ + -keyout client_key_app_001.pem \ + -x509 \ + -days 36500 \ + -out client_cert_app_001.pem diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatetrust.sh b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatetrust.sh new file mode 100644 index 000000000..052afc9d7 --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/generatetrust.sh @@ -0,0 +1,8 @@ +keytool -genkey \ + -dname "cn=CLIENT_APP_01" \ + -alias truststorekey \ + -keyalg RSA \ + -keystore ./client-truststore.p12 \ + -keypass ${KEYSTORE_PASSWORD} \ + -storepass ${TRUSTSTORE_PASSWORD} \ + -storetype pkcs12 diff --git a/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/importkey.sh b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/importkey.sh new file mode 100644 index 000000000..6bca0032f --- /dev/null +++ b/jdk_17_maven/cs/rest/digitalbanking/src/main/resources/ssl/importkey.sh @@ -0,0 +1,4 @@ +keytool -import \ + -keystore ./client-truststore.p12 \ + -file ./proxy_cert.pem \ + -alias redis-cluster-crt