From 3d03d755f6728562752a22eb6c0a16870eae71ad Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Tue, 15 Apr 2025 17:22:50 +0200 Subject: [PATCH] chore: vibe debuging untill it started working --- .gitignore | 129 ++++++++++ .../com/anomaly/model/TransactionAlert.java | 106 ++++++++ .../anomaly/visualizer/AlertVisualizer.java | 2 +- .../java/com/anomaly/model/Transaction.java | 90 +++++++ .../com/anomaly/model/TransactionAlert.java | 94 +++++-- .../java/com/anomaly/model/Transaction.java | 65 +++++ run_anomaly_detection.sh | 233 ++++++++++++++++++ .../java/com/anomaly/model/Transaction.java | 85 +++++++ 8 files changed, 779 insertions(+), 25 deletions(-) create mode 100644 .gitignore create mode 100644 alarm-visualizer/src/main/java/com/anomaly/model/TransactionAlert.java create mode 100644 anomaly-detector/src/main/java/com/anomaly/model/Transaction.java create mode 100644 kafka-consumer-visualizer/src/main/java/com/anomaly/model/Transaction.java create mode 100755 run_anomaly_detection.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..749d0d2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath +# Docker project generated files to ignore +# if you want to ignore files created by your editor/tools, +# please consider a global .gitignore https://help.github.com/articles/ignoring-files +.vagrant* +bin +docker/docker +.*.swp +a.out +*.orig +build_src +.flymake* +.idea +.DS_Store +docs/_build +docs/_static +docs/_templates +.gopath/ +.dotcloud +*.test +bundles/ +.hg/ +.git/ +vendor/pkg/ +pyenv +Vagrantfile +dist +*classes +*.class +target/ +build/ +build_eclipse/ +out/ +.gradle/ +.vscode/ +lib_managed/ +src_managed/ +project/boot/ +project/plugins/project/ +patch-process/* +.idea +.svn +.classpath +/.metadata +/.recommenders +*~ +*# +.#* +rat.out +TAGS +*.iml +.project +.settings +*.ipr +*.iws +.vagrant +Vagrantfile.local +/logs +.DS_Store + +config/server-* +config/zookeeper-* +gradle/wrapper/*.jar +gradlew.bat + +results +tests/results +.ducktape +tests/.ducktape +tests/venv +.cache + +docs/generated/ + +.release-settings.json + +kafkatest.egg-info/ +systest/ +*.swp +jmh-benchmarks/generated +jmh-benchmarks/src/main/generated +**/.jqwik-database +**/src/generated +**/src/generated-test +storage/kafka-tiered-storage/ + +docker/test/report_*.html +kafka.Kafka +__pycache__ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* \ No newline at end of file diff --git a/alarm-visualizer/src/main/java/com/anomaly/model/TransactionAlert.java b/alarm-visualizer/src/main/java/com/anomaly/model/TransactionAlert.java new file mode 100644 index 00000000..d115154f --- /dev/null +++ b/alarm-visualizer/src/main/java/com/anomaly/model/TransactionAlert.java @@ -0,0 +1,106 @@ +package com.anomaly.model; + +import java.time.Instant; + +public class TransactionAlert { + private String alertType; + private Instant alertTime; + private Instant timestamp; + private String cardId; + private String userId; + private double amount; + private double latitude; + private double longitude; + private String message; + + // Default constructor for Gson deserialization + public TransactionAlert() { + } + + public TransactionAlert(String alertType, Instant alertTime, Instant timestamp, + String cardId, String userId, double amount, + double latitude, double longitude, String message) { + this.alertType = alertType; + this.alertTime = alertTime; + this.timestamp = timestamp; + this.cardId = cardId; + this.userId = userId; + this.amount = amount; + this.latitude = latitude; + this.longitude = longitude; + this.message = message; + } + + // Getters and setters + public String getAlertType() { + return alertType; + } + + public void setAlertType(String alertType) { + this.alertType = alertType; + } + + public Instant getAlertTime() { + return alertTime; + } + + public void setAlertTime(Instant alertTime) { + this.alertTime = alertTime; + } + + public Instant getTimestamp() { + return timestamp; + } + + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/alarm-visualizer/src/main/java/com/anomaly/visualizer/AlertVisualizer.java b/alarm-visualizer/src/main/java/com/anomaly/visualizer/AlertVisualizer.java index 9a81205c..4c058171 100644 --- a/alarm-visualizer/src/main/java/com/anomaly/visualizer/AlertVisualizer.java +++ b/alarm-visualizer/src/main/java/com/anomaly/visualizer/AlertVisualizer.java @@ -267,7 +267,7 @@ public class AlertVisualizer { dialog.setVisible(true); // Auto-dismiss after 5 seconds - Timer timer = new Timer(5000, e -> dialog.dispose()); + javax.swing.Timer timer = new javax.swing.Timer(5000, e -> dialog.dispose()); timer.setRepeats(false); timer.start(); }); diff --git a/anomaly-detector/src/main/java/com/anomaly/model/Transaction.java b/anomaly-detector/src/main/java/com/anomaly/model/Transaction.java new file mode 100644 index 00000000..5ced0318 --- /dev/null +++ b/anomaly-detector/src/main/java/com/anomaly/model/Transaction.java @@ -0,0 +1,90 @@ +package com.anomaly.model; + +import java.time.Instant; + +/** + * Represents a financial transaction with location data. + */ +public class Transaction { + private String cardId; + private String userId; + private double amount; + private double latitude; + private double longitude; + private Instant timestamp; + + // Default constructor for deserialization + public Transaction() { + } + + public Transaction(String cardId, String userId, double amount, + double latitude, double longitude, Instant timestamp) { + this.cardId = cardId; + this.userId = userId; + this.amount = amount; + this.latitude = latitude; + this.longitude = longitude; + this.timestamp = timestamp; + } + + // Getters and setters + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public Instant getTimestamp() { + return timestamp; + } + + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "Transaction{" + + "cardId='" + cardId + '\'' + + ", userId='" + userId + '\'' + + ", amount=" + amount + + ", latitude=" + latitude + + ", longitude=" + longitude + + ", timestamp=" + timestamp + + '}'; + } +} diff --git a/anomaly-detector/src/main/java/com/anomaly/model/TransactionAlert.java b/anomaly-detector/src/main/java/com/anomaly/model/TransactionAlert.java index 89fddf4e..8c8131cd 100644 --- a/anomaly-detector/src/main/java/com/anomaly/model/TransactionAlert.java +++ b/anomaly-detector/src/main/java/com/anomaly/model/TransactionAlert.java @@ -2,6 +2,9 @@ package com.anomaly.model; import java.time.Instant; +/** + * Represents an alert generated when an anomaly is detected in a transaction. + */ public class TransactionAlert { private String alertType; private String cardId; @@ -11,14 +14,13 @@ public class TransactionAlert { private double longitude; private Instant timestamp; private String message; - private Instant alertTime; public TransactionAlert() { - this.alertTime = Instant.now(); } - public TransactionAlert(String alertType, String cardId, String userId, double amount, - double latitude, double longitude, Instant timestamp, String message) { + public TransactionAlert(String alertType, String cardId, String userId, + double amount, double latitude, double longitude, + Instant timestamp, String message) { this.alertType = alertType; this.cardId = cardId; this.userId = userId; @@ -27,28 +29,72 @@ public class TransactionAlert { this.longitude = longitude; this.timestamp = timestamp; this.message = message; - this.alertTime = Instant.now(); } // Getters and setters - public String getAlertType() { return alertType; } - public void setAlertType(String alertType) { this.alertType = alertType; } - public String getCardId() { return cardId; } - public void setCardId(String cardId) { this.cardId = cardId; } - public String getUserId() { return userId; } - public void setUserId(String userId) { this.userId = userId; } - public double getAmount() { return amount; } - public void setAmount(double amount) { this.amount = amount; } - public double getLatitude() { return latitude; } - public void setLatitude(double latitude) { this.latitude = latitude; } - public double getLongitude() { return longitude; } - public void setLongitude(double longitude) { this.longitude = longitude; } - public Instant getTimestamp() { return timestamp; } - public void setTimestamp(Instant timestamp) { this.timestamp = timestamp; } - public String getMessage() { return message; } - public void setMessage(String message) { this.message = message; } - public Instant getAlertTime() { return alertTime; } - public void setAlertTime(Instant alertTime) { this.alertTime = alertTime; } + public String getAlertType() { + return alertType; + } + + public void setAlertType(String alertType) { + this.alertType = alertType; + } + + public String getCardId() { + return cardId; + } + + public void setCardId(String cardId) { + this.cardId = cardId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public Instant getTimestamp() { + return timestamp; + } + + public void setTimestamp(Instant timestamp) { + this.timestamp = timestamp; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } @Override public String toString() { @@ -59,8 +105,8 @@ public class TransactionAlert { ", amount=" + amount + ", latitude=" + latitude + ", longitude=" + longitude + + ", timestamp=" + timestamp + ", message='" + message + '\'' + - ", alertTime=" + alertTime + '}'; } } diff --git a/kafka-consumer-visualizer/src/main/java/com/anomaly/model/Transaction.java b/kafka-consumer-visualizer/src/main/java/com/anomaly/model/Transaction.java new file mode 100644 index 00000000..9beddc47 --- /dev/null +++ b/kafka-consumer-visualizer/src/main/java/com/anomaly/model/Transaction.java @@ -0,0 +1,65 @@ +package com.anomaly.model; + +/** + * Represents a financial transaction with amount and available credit limit information. + */ +public class Transaction { + private double amount; + private double availableLimit; + private String cardNumber; + private String timestamp; + + // Default constructor for deserialization + public Transaction() { + } + + // Full constructor + public Transaction(double amount, double availableLimit, String cardNumber, String timestamp) { + this.amount = amount; + this.availableLimit = availableLimit; + this.cardNumber = cardNumber; + this.timestamp = timestamp; + } + + public double getAmount() { + return amount; + } + + public void setAmount(double amount) { + this.amount = amount; + } + + public double getAvailableLimit() { + return availableLimit; + } + + public void setAvailableLimit(double availableLimit) { + this.availableLimit = availableLimit; + } + + public String getCardNumber() { + return cardNumber; + } + + public void setCardNumber(String cardNumber) { + this.cardNumber = cardNumber; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "Transaction{" + + "amount=" + amount + + ", availableLimit=" + availableLimit + + ", cardNumber='" + cardNumber + '\'' + + ", timestamp='" + timestamp + '\'' + + '}'; + } +} diff --git a/run_anomaly_detection.sh b/run_anomaly_detection.sh new file mode 100755 index 00000000..1c25c8ae --- /dev/null +++ b/run_anomaly_detection.sh @@ -0,0 +1,233 @@ +#!/bin/bash + +# Colors for output +GREEN='\033[0;32m' +BLUE='\033[0;34m' +RED='\033[0;31m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +PROJECT_ROOT=$(pwd) +TOPICS=("transactions" "alerts") + +function check_prerequisites { + echo -e "${BLUE}Checking prerequisites...${NC}" + + # Check for Java + if ! command -v java &> /dev/null; then + echo -e "${RED}Java is not installed. Please install JDK 11 or higher.${NC}" + exit 1 + fi + + # Check for Maven + if ! command -v mvn &> /dev/null; then + echo -e "${RED}Maven is not installed. Please install Maven.${NC}" + exit 1 + fi + + # Check for Docker + if ! command -v docker &> /dev/null; then + echo -e "${RED}Docker is not installed. Please install Docker.${NC}" + exit 1 + fi + + # Check for docker-compose + if ! command -v docker-compose &> /dev/null; then + echo -e "${RED}Docker Compose is not installed. Please install Docker Compose.${NC}" + exit 1 + fi + + echo -e "${GREEN}All prerequisites are met.${NC}" +} + +function build_projects { + echo -e "${BLUE}Building all projects...${NC}" + + # Build each project + for project in "transaction-simulator" "kafka-consumer-visualizer" "anomaly-detector" "alarm-visualizer"; do + echo -e "${YELLOW}Building $project...${NC}" + cd "$PROJECT_ROOT/$project" + mvn clean package -DskipTests + + if [ $? -ne 0 ]; then + echo -e "${RED}Failed to build $project.${NC}" + exit 1 + fi + done + + cd "$PROJECT_ROOT" + echo -e "${GREEN}All projects built successfully.${NC}" +} + +function start_infrastructure { + echo -e "${BLUE}Starting Kafka and Flink containers...${NC}" + + docker-compose up -d + + # Wait for Kafka to be ready + echo -e "${YELLOW}Waiting for Kafka to be ready...${NC}" + sleep 10 + + # Create Kafka topics + for topic in "${TOPICS[@]}"; do + echo -e "${YELLOW}Creating Kafka topic: $topic${NC}" + docker-compose exec kafka kafka-topics --create \ + --topic "$topic" \ + --bootstrap-server localhost:9092 \ + --partitions 3 \ + --replication-factor 1 \ + --if-not-exists + done + + echo -e "${GREEN}Infrastructure is up and running.${NC}" +} + +function start_applications { + echo -e "${BLUE}Starting applications...${NC}" + + # Start anomaly detector (Flink app) + echo -e "${YELLOW}Starting Anomaly Detector (Flink App)...${NC}" + cd "$PROJECT_ROOT/anomaly-detector" + java -jar target/anomaly-detector-1.0-SNAPSHOT.jar > "$PROJECT_ROOT/logs/anomaly-detector.log" 2>&1 & + ANOMALY_DETECTOR_PID=$! + echo $ANOMALY_DETECTOR_PID > "$PROJECT_ROOT/logs/anomaly-detector.pid" + + sleep 5 + + # Start alarm visualizer + echo -e "${YELLOW}Starting Alarm Visualizer...${NC}" + cd "$PROJECT_ROOT/alarm-visualizer" + java -jar target/alarm-visualizer-1.0-SNAPSHOT.jar > "$PROJECT_ROOT/logs/alarm-visualizer.log" 2>&1 & + ALARM_VISUALIZER_PID=$! + echo $ALARM_VISUALIZER_PID > "$PROJECT_ROOT/logs/alarm-visualizer.pid" + + # Start test consumer/visualizer + echo -e "${YELLOW}Starting Test Consumer Visualizer...${NC}" + cd "$PROJECT_ROOT/kafka-consumer-visualizer" + java -jar target/kafka-consumer-visualizer-1.0-SNAPSHOT.jar > "$PROJECT_ROOT/logs/consumer-visualizer.log" 2>&1 & + CONSUMER_PID=$! + echo $CONSUMER_PID > "$PROJECT_ROOT/logs/consumer-visualizer.pid" + + sleep 5 + + # Start transaction simulator + echo -e "${YELLOW}Starting Transaction Simulator...${NC}" + cd "$PROJECT_ROOT/transaction-simulator" + java -jar target/transaction-simulator-1.0-SNAPSHOT.jar > "$PROJECT_ROOT/logs/transaction-simulator.log" 2>&1 & + SIMULATOR_PID=$! + echo $SIMULATOR_PID > "$PROJECT_ROOT/logs/transaction-simulator.pid" + + cd "$PROJECT_ROOT" + echo -e "${GREEN}All applications are running.${NC}" + echo -e "${GREEN}Log files are available in the logs directory.${NC}" +} + +function stop_applications { + echo -e "${BLUE}Stopping applications...${NC}" + + # Stop all Java applications + if [ -f "$PROJECT_ROOT/logs/transaction-simulator.pid" ]; then + kill $(cat "$PROJECT_ROOT/logs/transaction-simulator.pid") 2>/dev/null + rm "$PROJECT_ROOT/logs/transaction-simulator.pid" + fi + + if [ -f "$PROJECT_ROOT/logs/consumer-visualizer.pid" ]; then + kill $(cat "$PROJECT_ROOT/logs/consumer-visualizer.pid") 2>/dev/null + rm "$PROJECT_ROOT/logs/consumer-visualizer.pid" + fi + + if [ -f "$PROJECT_ROOT/logs/anomaly-detector.pid" ]; then + kill $(cat "$PROJECT_ROOT/logs/anomaly-detector.pid") 2>/dev/null + rm "$PROJECT_ROOT/logs/anomaly-detector.pid" + fi + + if [ -f "$PROJECT_ROOT/logs/alarm-visualizer.pid" ]; then + kill $(cat "$PROJECT_ROOT/logs/alarm-visualizer.pid") 2>/dev/null + rm "$PROJECT_ROOT/logs/alarm-visualizer.pid" + fi + + echo -e "${GREEN}All applications stopped.${NC}" +} + +function stop_infrastructure { + echo -e "${BLUE}Stopping infrastructure...${NC}" + + docker-compose down + + echo -e "${GREEN}Infrastructure stopped.${NC}" +} + +function show_logs { + echo -e "${BLUE}Available logs:${NC}" + ls -l "$PROJECT_ROOT/logs" + + echo -e "${YELLOW}Use 'tail -f logs/[filename]' to view a specific log.${NC}" +} + +function print_usage { + echo -e "${BLUE}Credit Card Transaction Anomaly Detection System${NC}" + echo -e "Usage: $0 [options]" + echo -e "Options:" + echo -e " ${GREEN}start${NC} Build and start the entire system" + echo -e " ${GREEN}stop${NC} Stop all components" + echo -e " ${GREEN}restart${NC} Restart the entire system" + echo -e " ${GREEN}status${NC} Check if components are running" + echo -e " ${GREEN}logs${NC} Show log files" +} + +function check_status { + echo -e "${BLUE}Checking system status...${NC}" + + # Check Docker containers + echo -e "${YELLOW}Docker containers:${NC}" + docker-compose ps + + # Check Java processes + echo -e "\n${YELLOW}Java applications:${NC}" + for app in "transaction-simulator" "consumer-visualizer" "anomaly-detector" "alarm-visualizer"; do + if [ -f "$PROJECT_ROOT/logs/$app.pid" ]; then + pid=$(cat "$PROJECT_ROOT/logs/$app.pid") + if ps -p $pid > /dev/null; then + echo -e "${GREEN}$app is running (PID: $pid)${NC}" + else + echo -e "${RED}$app is not running (stale PID file)${NC}" + fi + else + echo -e "${RED}$app is not running${NC}" + fi + done +} + +# Create logs directory +mkdir -p "$PROJECT_ROOT/logs" + +# Parse command-line arguments +case "$1" in + start) + check_prerequisites + build_projects + start_infrastructure + start_applications + ;; + stop) + stop_applications + stop_infrastructure + ;; + restart) + stop_applications + stop_infrastructure + sleep 5 + start_infrastructure + sleep 5 + start_applications + ;; + status) + check_status + ;; + logs) + show_logs + ;; + *) + print_usage + ;; +esac diff --git a/transaction-simulator/src/main/java/com/anomaly/model/Transaction.java b/transaction-simulator/src/main/java/com/anomaly/model/Transaction.java index e69de29b..b45b3a31 100644 --- a/transaction-simulator/src/main/java/com/anomaly/model/Transaction.java +++ b/transaction-simulator/src/main/java/com/anomaly/model/Transaction.java @@ -0,0 +1,85 @@ +package com.anomaly.model; + +import java.time.Instant; +import java.util.Objects; + +public class Transaction { + private final String cardId; + private final String userId; + private final double latitude; + private final double longitude; + private final double amount; + private final double availableLimit; + private final Instant timestamp; + + public Transaction(String cardId, String userId, double latitude, double longitude, + double amount, double availableLimit, Instant timestamp) { + this.cardId = cardId; + this.userId = userId; + this.latitude = latitude; + this.longitude = longitude; + this.amount = amount; + this.availableLimit = availableLimit; + this.timestamp = timestamp; + } + + public String getCardId() { + return cardId; + } + + public String getUserId() { + return userId; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public double getAmount() { + return amount; + } + + public double getAvailableLimit() { + return availableLimit; + } + + public Instant getTimestamp() { + return timestamp; + } + + @Override + public String toString() { + return "Transaction{" + + "cardId='" + cardId + '\'' + + ", userId='" + userId + '\'' + + ", latitude=" + latitude + + ", longitude=" + longitude + + ", amount=" + amount + + ", availableLimit=" + availableLimit + + ", timestamp=" + timestamp + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Transaction that = (Transaction) o; + return Double.compare(that.latitude, latitude) == 0 && + Double.compare(that.longitude, longitude) == 0 && + Double.compare(that.amount, amount) == 0 && + Double.compare(that.availableLimit, availableLimit) == 0 && + Objects.equals(cardId, that.cardId) && + Objects.equals(userId, that.userId) && + Objects.equals(timestamp, that.timestamp); + } + + @Override + public int hashCode() { + return Objects.hash(cardId, userId, latitude, longitude, amount, availableLimit, timestamp); + } +}