first commit

This commit is contained in:
2025-12-11 21:50:58 +01:00
commit 506ee6ef22
18 changed files with 894 additions and 0 deletions

39
week2_TinsaeGhilay/Task2/.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.kotlin
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

8
week2_TinsaeGhilay/Task2/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

15
week2_TinsaeGhilay/Task2/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="KubernetesApiProvider"><![CDATA[{}]]></component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21 (3)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
week2_TinsaeGhilay/Task2/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.distributed</groupId>
<artifactId>Task2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.18.4</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.23.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,206 @@
package org.distributed;
/**
* ChatHandler.java
* by Tinsae Ghilay
* Handles chat session, message sending and receiving using JMS queues.
* Uses ActiveMQ as the message broker.
* done for Distributed Systems Course - Week 2 Task 2
* Date: June 2024
*/
import java.util.Scanner;
import javax.jms.*;
import org.apache.activemq.ActiveMQConnectionFactory;
// ChatHandler class to manage chat sessions
public class ChatHandler {
// chatting ids
private String userId, corespondent;
private Connection connection;
private Session session;
int status = 0; // 0: offline, 1: online
// Initialize connection and session
public void initializeSession() throws JMSException {
String BROKER_URL = "tcp://localhost:61616";
ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
this.connection = factory.createConnection();
this.connection.start();
this.session = this.connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
}
// Start continuous conversation with multiple receivers
public void startConversation(Scanner sc) throws JMSException {
// Initialize all producers and consumers
Thread t = setupReceiver();
// Continuous input loop
try {
while (sc.hasNextLine()) {
String line = sc.nextLine();
// Send message to receiver
sendMessage(createProducer(), line);
// Exit condition
if (line.equalsIgnoreCase("exit")) {
System.out.println("Exiting conversation...");
break;
}
}
} catch (Exception e) {
System.err.println("Error in continuous conversation: " + e.getMessage());
} finally {
t.interrupt();
}
}
// Setup producer and consumer for a receiver
private Thread setupReceiver() throws JMSException {
MessageConsumer consumer = createConsumer();
return getThread(consumer);
}
// Create producer queue for sending messages
private MessageProducer createProducer() throws JMSException {
String from = "queue_" + userId;
Queue prod = session.createQueue(from);
return session.createProducer(prod);
}
// Create consumer queue for receiving messages
private MessageConsumer createConsumer() throws JMSException {
String to = "queue_" + getCorespondent();
Queue cons = session.createQueue(to);
return session.createConsumer(cons);
}
// Send a message to the producer
private void sendMessage(MessageProducer producer, String line) throws JMSException {
TextMessage m = session.createTextMessage(line);
m.setStringProperty("sender", userId);
producer.send(m);
}
// Close connection and session
public void closeSession() throws JMSException {
if (session != null) {
session.close();
}
if (connection != null) {
connection.close();
}
}
// Returns a thread object to handle receiving messages
private Thread getThread(MessageConsumer consumer) {
Thread receivingThread = new Thread(() -> {
try {
// continously listen for messages
while (!Thread.currentThread().isInterrupted()) {
Message msg = consumer.receive(300);
if (msg instanceof TextMessage tm) {
// Status handling for online/offline
if(tm.getText().isBlank() || tm.getText().isEmpty()) {
setStatus(1);
continue;
}
// Exit condition because correspondent went offline
if(tm.getText().equalsIgnoreCase("exit")) {
setStatus(0);
continue;
}
// Display received message
String sender = tm.getStringProperty("sender");
String body = tm.getText();
System.out.println("[" + sender + "]: " + body);
}
}
} catch (javax.jms.JMSException e) {
// Silently handle interruption - normal shutdown behavior
if (!Thread.currentThread().isInterrupted()) {
System.err.println("Error receiving message: " + e.getMessage());
}
}
});
receivingThread.start();
// we are returning this so we can interrupt it later
return receivingThread;
}
// Prompt for user ID
public void promptForUser(Scanner sc){
System.out.print("Enter your user ID: ");
setUserId(prompt(sc));
// Instructions
System.out.print("Welcome "+getUserId());
System.out.println(" -> Type 'exit' to quit.");
}
// Prompt for correspondent ID
public void promptForCorespondent(Scanner sc){
System.out.print("Who do you want to chat with? ");
setCorespondent(prompt(sc));
System.out.println("You can chat with: " + getCorespondent());
}
// Generic prompt method prompts for whatever we need
private String prompt(Scanner sc) {
String user = "";
while (user.isEmpty()) {
try {
user = sc.next();
} catch (Exception e) {
System.err.println("Error reading correspondent ID: " + e.getMessage());
return null;
}
}
return user;
}
// Setters and getters
// user
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserId() {
return userId;
}
// correspondent
public String getCorespondent() {
return corespondent;
}
public void setCorespondent(String corespondent) {
this.corespondent = corespondent;
}
// update status of correspondent and print status message
private void setStatus(int status) {
// just incase of duplicate status messages, if status is same, return
if(this.status == status) {
return;
}
this.status = status;
if(status == 0) {
System.out.println(getCorespondent()+" is now offline.");
} else {
System.out.println(getCorespondent()+" is now online.");
}
}
}

View File

@@ -0,0 +1,37 @@
package org.distributed;
/**
* Main.java
* by Tinsae Ghilay
* Entry point for the chat application.
* done for Distributed Systems Course - Week 2 Task 2
* Date: June 2024
*/
import java.util.Scanner;
public class Main {
// entry point
public static void main(String[] args) throws Exception {
// create a client
ChatHandler handler = new ChatHandler();
// init connection and session session
handler.initializeSession();
// create scanner for user input
Scanner sc = new Scanner(System.in);
// log in user
handler.promptForUser(sc);
// specify correspondent
handler.promptForCorespondent(sc);
// start conversation
handler.startConversation(sc);
// close session after all receivers are processed
handler.closeSession();
}
}