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

Feature/event project kafka done! (Close #14) #32

Merged
merged 3 commits into from
Jun 4, 2024
Merged
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
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

<!-- Message Broker -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>

<!-- Caching -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -106,6 +112,11 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.seyed.ali.timeentryservice.event;

import com.seyed.ali.timeentryservice.model.enums.OperationType;
import com.seyed.ali.timeentryservice.model.payload.ProjectDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Service;

@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectEventListener {

private final ProjectEventService projectEventService;

@KafkaListener(
topics = "${spring.kafka.topic.name}",
groupId = "${spring.kafka.consumer.group-id}" // if we change the group-id name, the events from the previous data will also be logged, otherwise, only the new events will be logged!
)
public void handleProjectEvent(@Payload ConsumerRecord<String, ProjectDTO> record, @Header("OperationType") String operationType) {
ProjectDTO projectDTO = record.value();
switch (OperationType.valueOf(operationType)) {
case DELETE -> this.projectEventService.handleDeleteOperation(projectDTO);
case DETACH -> this.projectEventService.handleDetachOperation(projectDTO);
default -> log.warn("\"{}\" operation type not supported.", operationType);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.seyed.ali.timeentryservice.event;

import com.seyed.ali.timeentryservice.model.payload.ProjectDTO;
import com.seyed.ali.timeentryservice.repository.TimeEntryRepository;
import com.seyed.ali.timeentryservice.service.interfaces.TimeEntryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor
public class ProjectEventService {

private final TimeEntryService timeEntryService;
private final TimeEntryRepository timeEntryRepository;

public void handleDeleteOperation(ProjectDTO projectDTO) {
log.info("\"Delete\" project, associated tasks & time entries: {}", projectDTO);
this.timeEntryRepository.findByProjectId(projectDTO.getProjectId())
.forEach(this.timeEntryService::deleteTimeEntry);
}

public void handleDetachOperation(ProjectDTO projectDTO) {
log.info("\"Detach\" project, associated tasks & time entries: {}", projectDTO);
this.timeEntryRepository.findByProjectId(projectDTO.getProjectId())
.forEach(timeEntry -> {
timeEntry.setProjectId(null);
timeEntry.setTaskId(null);
this.timeEntryRepository.save(timeEntry);
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.seyed.ali.timeentryservice.model.enums;

public enum OperationType {

DELETE, DETACH

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.seyed.ali.timeentryservice.model.payload;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
* DTO for {@link com.seyed.ali.projectservice.model.domain.Project}
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProjectDTO implements Serializable {

@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "Unique identifier for the project", example = "12345")
private String projectId;

@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "The project name", example = "Microservices-Springboot")
private String projectName;

@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "The project name", example = "Learning microservices is really exciting and HARD ;)")
private String projectDescription;

@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "The task associated with the project", implementation = TaskDTO.class)
private List<TaskDTO> taskDTO = new ArrayList<>();

public ProjectDTO(String projectId, String projectName, String projectDescription) {
this.projectId = projectId;
this.projectName = projectName;
this.projectDescription = projectDescription;
this.taskDTO = new ArrayList<>();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.seyed.ali.timeentryservice.model.domain.TimeEntry;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface TimeEntryRepository extends JpaRepository<TimeEntry, String> {
Expand All @@ -11,4 +12,8 @@ public interface TimeEntryRepository extends JpaRepository<TimeEntry, String> {

TimeEntry findByUserIdAndTimeEntryId(String userId, String timeEntryId);

List<TimeEntry> findByProjectId(String projectId);

List<TimeEntry> findByTaskId(String taskId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,19 @@ public void deleteTimeEntry(String timeEntryId) {
this.timeEntryRepository.deleteById(timeEntryId);
}

/**
* {@inheritDoc}
*/
@Override
@Transactional
@CacheEvict(
cacheNames = TimeEntryCacheManager.TIME_ENTRY_CACHE,
key = "#timeEntry.timeEntryId"
)
public void deleteTimeEntry(TimeEntry timeEntry) {
TimeEntry foundTimeEntry = this.timeEntryRepository.findById(timeEntry.getTimeEntryId())
.orElseThrow(() -> new ResourceNotFoundException("The provided timeEntryId does not exist"));
this.timeEntryRepository.delete(foundTimeEntry);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@ public interface TimeEntryService {
TimeEntry updateTimeEntryManually(String id, TimeEntryDTO timeEntryDTO);

/**
* Deletes a time entry.
* Deletes a time entry by ID.
*
* @param timeEntryId The ID of the time entry to be deleted.
*/
void deleteTimeEntry(String timeEntryId);

/**
* Deletes a time entry.
*
* @param timeEntry The time entry to be deleted.
*/
void deleteTimeEntry(TimeEntry timeEntry);

}
21 changes: 20 additions & 1 deletion src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,23 @@ authentication:
service:
user-persistence-controller:
base-url: http://${AUTHENTICATION_SERVICE_HANDLE_USER_BASE_URL:localhost:8081}/keycloak-user
handle-user-url: /handle-user
handle-user-url: /handle-user

--- # Kafka
spring:
kafka:
consumer:
bootstrap-servers: localhost:9092
group-id: project_group_timeentry
auto-offset-reset: earliest

#configure deserialize classes for key & value pair
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
spring.json.trusted.packages: "*"
spring.json.type.mapping: ProjectEvent:com.seyed.ali.timeentryservice.model.payload.ProjectDTO

#custom
topic:
name: project_name
21 changes: 20 additions & 1 deletion src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,23 @@ authentication:
service:
user-persistence-controller:
base-url: http://${AUTHENTICATION_SERVICE_HANDLE_USER_BASE_URL:localhost:8081}/keycloak-user
handle-user-url: /handle-user
handle-user-url: /handle-user

--- # Kafka
spring:
kafka:
consumer:
bootstrap-servers: localhost:9092
group-id: project_group_timeentry
auto-offset-reset: earliest

#configure deserialize classes for key & value pair
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
spring.json.trusted.packages: "*"
spring.json.type.mapping: ProjectEvent:com.seyed.ali.timeentryservice.model.payload.ProjectDTO

#custom
topic:
name: project_name