Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apache Cassandra Implementation for Chat Service #296

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ services:
volumes:
- ./data/minio:/data

cassandra-seed:
image: cassandra:latest
container_name: cassandra-seed
environment:
- CASSANDRA_CLUSTER_NAME=remsfal-cassandra-cluster
- CASSANDRA_NUM_TOKENS=8
- CASSANDRA_SEEDS=cassandra-seed
- CASSANDRA_USER=admin
- CASSANDRA_PASSWORD=admin
ports:
- "9042:9042"
- "7000:7000"

cassandra-node1:
image: cassandra:latest
container_name: cassandra-node1
environment:
- CASSANDRA_CLUSTER_NAME=remsfal-cassandra-cluster
- CASSANDRA_SEEDS=cassandra-seed
ports:
- "9043:9042" # Alternative port mapping for node1
- "7001:7000"


networks:
remsfal:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.remsfal.core.api.project;

import de.remsfal.core.json.project.ChatMessageJson;
import de.remsfal.core.model.project.ChatSessionModel;
import de.remsfal.core.validation.UUID;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
Expand Down Expand Up @@ -48,7 +47,8 @@ public interface ChatEndpoint {
@APIResponse(responseCode = "500", description = "Internal server error")
@APIResponse(responseCode = "401", description = "No user authentication provided via session cookie")
Response getChatSession(
@PathParam("sessionId") @NotNull @UUID String sessionId);
@PathParam("sessionId") @NotNull @UUID String sessionId
);

@DELETE
@Path("/{sessionId}")
Expand All @@ -75,7 +75,7 @@ Response deleteChatSession(
Response updateChatSessionStatus(
@PathParam("sessionId") @NotNull @UUID String sessionId,
@Parameter(description = "New status for the chat session", required = true)
@Valid @NotNull ChatSessionModel.Status status);
@Valid @NotNull String status);

@POST
@Path("/{sessionId}")
Expand Down Expand Up @@ -131,7 +131,7 @@ Response changeParticipantRole(
@Parameter(description = "The participant ID", required = true) @PathParam("participantId")
@NotNull @UUID String participantId,
@Parameter(description = "New role for the participant", required = true)
@Valid @NotNull ChatSessionModel.ParticipantRole role);
@Valid @NotNull String role);

@DELETE
@Path("/{sessionId}/participants/{participantId}")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package de.remsfal.core.json.project;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import de.remsfal.core.model.UserModel;
import de.remsfal.core.model.project.ChatMessageModel;
import de.remsfal.core.model.project.ChatSessionModel;
import de.remsfal.core.validation.UUID;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.Null;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.immutables.value.Value;

import java.util.Date;
import java.time.Instant;
import java.util.UUID;

/**
* @author: Parham Rahmani [parham.rahmani@student.htw-berlin.de]
Expand All @@ -27,22 +23,19 @@ public abstract class ChatMessageJson implements ChatMessageModel {
@Null
@Nullable
@Override
@UUID
public abstract String getId();
public abstract UUID getMessageId();

@Nullable
@Override
@UUID
public abstract String getChatSessionId();
public abstract UUID getChatSessionId();

@Nullable
@Override
@UUID
public abstract String getSenderId();
public abstract UUID getSenderId();

@Nullable
@Override
public abstract ContentType getContentType();
public abstract String getContentType();

@Nullable
@Override
Expand All @@ -56,30 +49,18 @@ public abstract class ChatMessageJson implements ChatMessageModel {
@Null
@Nullable
@Override
public abstract Date getTimestamp();

@Null
@Nullable
@Override
@JsonIgnore
public abstract ChatSessionModel getChatSession();

@Null
@Nullable
@Override
@JsonIgnore
public abstract UserModel getSender();
public abstract Instant getCreatedAt();

public static ChatMessageJson valueOf(final ChatMessageModel model)
{
return ImmutableChatMessageJson.builder()
.id(model.getId())
.messageId(model.getMessageId())
.chatSessionId(model.getChatSessionId())
.senderId(model.getSenderId())
.contentType(model.getContentType())
.content(model.getContent())
.url(model.getUrl())
.timestamp(model.getTimestamp())
.createdAt(model.getCreatedAt())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package de.remsfal.core.json.project;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import de.remsfal.core.model.project.ChatSessionModel;
import de.remsfal.core.validation.UUID;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.Null;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.immutables.value.Value;

import java.util.Date;
import java.util.List;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;

/**
* @author: Parham Rahmani [parham.rahmani@student.htw-berlin.de]
Expand All @@ -24,63 +21,47 @@
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public abstract class ChatSessionJson implements ChatSessionModel {

@Null
@Override
@UUID
public abstract String getId();
public abstract UUID getSessionId();

@Null
@Nullable
@Override
@UUID
public abstract String getProjectId();
public abstract UUID getProjectId();

@Null
@Nullable
@Override
@UUID
public abstract String getTaskId();
public abstract UUID getTaskId();

@Nullable
@Override
public abstract TaskType getTaskType();
public abstract String getTaskType();

@Nullable
@Override
@JsonIgnore
public abstract Map<String, ParticipantRole> getParticipants();
public abstract Map<java.util.UUID, String> getParticipants();

@Nullable
@Override
public abstract Status getStatus();


@Null
@Nullable
@Override
@JsonIgnore
public abstract List<ChatMessageJson> getMessages();
public abstract String getStatus();

@Null
@Nullable
@Override
public abstract Date getCreatedAt();
public abstract Instant getCreatedAt();

@Null
@Nullable
@Override
public abstract Date getModifiedAt();
public abstract Instant getModifiedAt();

public static ChatSessionJson valueOf(final ChatSessionModel model) {
return ImmutableChatSessionJson.builder()
.id(model.getId())
.sessionId(model.getSessionId())
.projectId(model.getProjectId())
.taskId(model.getTaskId())
.taskType(model.getTaskType())
.status(model.getStatus())
.messages(model.getMessages().stream()
.map(ChatMessageJson::valueOf)
.toList())
.createdAt(model.getCreatedAt())
.modifiedAt(model.getModifiedAt())
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
package de.remsfal.core.model.project;

import de.remsfal.core.model.UserModel;

import java.util.Date;
import java.time.Instant;
import java.util.UUID;

/**
* @author: Parham Rahmani [parham.rahmani@student.htw-berlin.de]
* Represents a chat message in Cassandra.
*/
public interface ChatMessageModel {

String getId();

ChatSessionModel getChatSession();

String getChatSessionId();

UserModel getSender();

String getSenderId();

UUID getChatSessionId(); // Partition key for horizontal scaling

enum ContentType {
TEXT,
FILE
}
UUID getMessageId(); // Unique ID for the message (Clustering column)

ContentType getContentType();
UUID getSenderId(); // ID of the sender

String getContent();
String getContentType(); // Content type (e.g., TEXT, FILE)

String getUrl();
String getContent(); // Text content of the message

Date getTimestamp();
String getUrl(); // File URL if the content type is FILE

Instant getCreatedAt(); // Timestamp when the message was created
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,27 @@
package de.remsfal.core.model.project;

import java.util.Date;
import java.util.List;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;

/**
* @author: Parham Rahmani [parham.rahmani@student.htw-berlin.de]
* Represents a chat session in Cassandra.
*/
public interface ChatSessionModel {

String getId();
UUID getProjectId(); // Partition key for horizontal scaling

String getProjectId();
UUID getSessionId(); // Unique ID for the session (Clustering column)

String getTaskId();
UUID getTaskId(); // ID of the associated task

enum TaskType {
DEFECT,
TASK
}
String getTaskType(); // Task type (e.g., DEFECT, TASK)

TaskType getTaskType();
String getStatus(); // Session status (e.g., OPEN, CLOSED, ARCHIVED)

Map<String, ParticipantRole> getParticipants();
Map<UUID, String> getParticipants(); // Map of participant ID to role

enum ParticipantRole {
INITIATOR,
HANDLER,
OBSERVER
}

List<? extends ChatMessageModel> getMessages();

Status getStatus();

enum Status {
OPEN,
CLOSED,
ARCHIVED
}

Date getCreatedAt();

Date getModifiedAt();
Instant getCreatedAt(); // Timestamp when the session was created

Instant getModifiedAt(); // Timestamp when the session was last modified
}
Loading
Loading