From db4217bec4e7e754c37a6d54ea5686b2af9adeaa Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Mon, 1 Dec 2025 00:16:57 -0300 Subject: [PATCH] Implement Composer Management with CRUD Operations - Add `Composer` entity with JPA annotations and database mapping. - Create repository, service, and delegate handlers for Composer CRUD operations: `create_composer`, `get_composers`, `get_composer_by_id`, `update_composer`, `delete_composer`. - Introduce Protobuf definitions for Composer messages. - Register Composer service and handlers in `DelegateActionManager`. - Add `ComposerMapper` to map between Protobuf and entity models. - Enhance error handling and logging for Composer operations. --- .../mediamanager/mapper/ComposerMapper.java | 38 +++++++ .../java/com/mediamanager/model/Composer.java | 31 ++++++ .../repository/ComposerRepository.java | 102 ++++++++++++++++++ .../service/composer/ComposerService.java | 70 ++++++++++++ .../delegate/DelegateActionManager.java | 11 ++ .../composer/CreateComposerHandler.java | 51 +++++++++ .../composer/DeleteComposerHandler.java | 53 +++++++++ .../composer/GetComposerByIdHandler.java | 57 ++++++++++ .../handler/composer/GetComposerHandler.java | 50 +++++++++ .../composer/UpdateComposerHandler.java | 56 ++++++++++ src/main/proto/composer.proto | 51 +++++++++ 11 files changed, 570 insertions(+) create mode 100644 src/main/java/com/mediamanager/mapper/ComposerMapper.java create mode 100644 src/main/java/com/mediamanager/model/Composer.java create mode 100644 src/main/java/com/mediamanager/repository/ComposerRepository.java create mode 100644 src/main/java/com/mediamanager/service/composer/ComposerService.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/composer/CreateComposerHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/composer/DeleteComposerHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerByIdHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/composer/UpdateComposerHandler.java create mode 100644 src/main/proto/composer.proto diff --git a/src/main/java/com/mediamanager/mapper/ComposerMapper.java b/src/main/java/com/mediamanager/mapper/ComposerMapper.java new file mode 100644 index 0000000..cf783b5 --- /dev/null +++ b/src/main/java/com/mediamanager/mapper/ComposerMapper.java @@ -0,0 +1,38 @@ +package com.mediamanager.mapper; + +import com.mediamanager.model.Composer; +import com.mediamanager.protocol.messages.ComposerMessages; + +public class ComposerMapper { + public static ComposerMessages.Composer toProtobuf(Composer entity) { + if (entity == null) { + return null; + } + ComposerMessages.Composer.Builder builder = ComposerMessages.Composer.newBuilder() + .setName(entity.getName()); + + Integer id = entity.getId(); + if (id != null && id > 0) { + builder.setId(id); + } + + return builder.build(); + + } + + public static Composer toEntity(ComposerMessages.Composer protobuf) { + if (protobuf == null) { + return null; + } + + Composer entity = new Composer(); + + if (protobuf.getId() > 0) { + entity.setId(protobuf.getId()); + } + + entity.setName(protobuf.getName()); + + return entity; + } +} diff --git a/src/main/java/com/mediamanager/model/Composer.java b/src/main/java/com/mediamanager/model/Composer.java new file mode 100644 index 0000000..965bf6f --- /dev/null +++ b/src/main/java/com/mediamanager/model/Composer.java @@ -0,0 +1,31 @@ +package com.mediamanager.model; + + +import jakarta.persistence.*; + +@Entity +@Table(name = "composer") +public class Composer { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(nullable = false) + private String name; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/mediamanager/repository/ComposerRepository.java b/src/main/java/com/mediamanager/repository/ComposerRepository.java new file mode 100644 index 0000000..6e1a2aa --- /dev/null +++ b/src/main/java/com/mediamanager/repository/ComposerRepository.java @@ -0,0 +1,102 @@ +package com.mediamanager.repository; + +import com.mediamanager.model.Composer; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class ComposerRepository { + private static final Logger logger = LogManager.getLogger(ComposerRepository.class); + + private final EntityManagerFactory entityManagerFactory; + + public ComposerRepository(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + } + + public Composer save(Composer composer) { + logger.debug("Saving composer: {}", composer.getName()); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try{ + //ToDo: Add Id Validation + //ToDo: Add to all Repositories + em.persist(composer); + em.getTransaction().commit(); + logger.debug("Composer saved with IS: {}", composer.getId()); + return composer; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error saving composer", e); + throw e; + }finally { + if (em.isOpen()) em.close(); + } + } + + public List findAll(){ + logger.debug("Finding all composers"); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + return em.createQuery("SELECT c FROM Composer c ORDER BY c.name", Composer.class).getResultList(); + } finally { + if (em.isOpen()) em.close(); + } + } + + public Optional findById(Integer id){ + logger.debug("Finding composer by ID: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + Composer composer = em.find(Composer.class, id); + return Optional.ofNullable(composer); + } finally { + if (em.isOpen()) em.close(); + } + } + + public Composer update(Composer composer){ + logger.debug("Updating composer ID: {}", composer.getId()); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try{ + Composer updated = em.merge(composer); + em.getTransaction().commit(); + logger.debug("Composer updated successfully"); + return updated; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error updating composer", e); + throw e; + } finally { + if (em.isOpen()) em.close(); + } + } + + public boolean deleteById(Integer id){ + logger.debug("Deleting composer by ID: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try{ + Composer composer = em.find(Composer.class, id); + if (composer == null) { + em.getTransaction().rollback(); + return false; + } + em.remove(composer); + em.getTransaction().commit(); + logger.debug("Composer deleted successfully"); + return true; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error deleting composer", e); + throw e; + }finally { + if (em.isOpen()) em.close(); + } + } +} diff --git a/src/main/java/com/mediamanager/service/composer/ComposerService.java b/src/main/java/com/mediamanager/service/composer/ComposerService.java new file mode 100644 index 0000000..4f2e5e7 --- /dev/null +++ b/src/main/java/com/mediamanager/service/composer/ComposerService.java @@ -0,0 +1,70 @@ +package com.mediamanager.service.composer; + +import com.mediamanager.model.Composer; +import com.mediamanager.repository.ComposerRepository; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class ComposerService { + private static final Logger logger = LogManager.getLogger(ComposerService.class); + + private final ComposerRepository composerRepository; + + public ComposerService(ComposerRepository composerRepository) { + this.composerRepository = composerRepository; + } + + public Composer createComposer(String name) { + logger.info("Creating composer: {}", name); + if(name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException("Composer name cannot be empty"); + } + Composer composer = new Composer(); + composer.setName(name.trim()); + return composerRepository.save(composer); + + + } + + public List getAllComposers() { + logger.info("Getting all composers"); + return composerRepository.findAll(); + } + + public Optional getComposerById(Integer id) { + logger.info("Getting composer by ID: {}", id); + return composerRepository.findById(id); + } + + public Optional updateComposer(Integer id, String name) { + logger.info("Updating composer ID {}: {}", id, name); + + if(name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException("Composer name cannot be empty"); + } + + Optional existingComposer = composerRepository.findById(id); + + if(existingComposer.isEmpty()) { + logger.warn("Composer not found with ID: {}", id); + return Optional.empty(); + } + + Composer composer = existingComposer.get(); + composer.setName(name.trim()); + + Composer updated = composerRepository.update(composer); + return Optional.of(updated); + + } + + public boolean deleteComposer(Integer id) { + logger.info("Deleting composer ID: {}", id); + return composerRepository.deleteById(id); + } + + +} diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index 69d36d6..eb4ae76 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -2,7 +2,9 @@ package com.mediamanager.service.delegate; import com.google.protobuf.ByteString; import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.repository.ComposerRepository; import com.mediamanager.repository.GenreRepository; +import com.mediamanager.service.composer.ComposerService; import com.mediamanager.service.delegate.annotation.Action; import com.mediamanager.service.genre.GenreService; @@ -49,6 +51,15 @@ public class DelegateActionManager { serviceLocator.register(GenreService.class, genreService); + + + + + ComposerRepository composerRepository = new ComposerRepository(entityManagerFactory); + ComposerService composerService = new ComposerService(composerRepository); + serviceLocator.register(ComposerService.class, composerService); + + serviceLocator.logRegisteredServices(); logger.info("Services initialized successfully"); diff --git a/src/main/java/com/mediamanager/service/delegate/handler/composer/CreateComposerHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/composer/CreateComposerHandler.java new file mode 100644 index 0000000..5ec5658 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/composer/CreateComposerHandler.java @@ -0,0 +1,51 @@ +package com.mediamanager.service.delegate.handler.composer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.ComposerMapper; +import com.mediamanager.model.Composer; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.ComposerMessages; +import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action("composer.create") +public class CreateComposerHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(CreateComposerHandler.class); + private final ComposerService composerService; + + public CreateComposerHandler(ComposerService composerService) { + this.composerService = composerService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + try{ + ComposerMessages.CreateComposerRequest CreateRequest = ComposerMessages.CreateComposerRequest + .parseFrom(requestPayload); + Composer composer = composerService.createComposer(CreateRequest.getName()); + ComposerMessages.Composer composerProto = ComposerMapper.toProtobuf(composer); + ComposerMessages.CreateComposerResponse createResponse = ComposerMessages.CreateComposerResponse + .newBuilder().setComposer(composerProto).build(); + return TransportProtocol.Response.newBuilder().setPayload(createResponse.toByteString()); + + } catch (IllegalArgumentException e){ + logger.error("Validation error", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(400) + .setPayload(ByteString.copyFromUtf8("Validation error: " + e.getMessage())); + + } catch (Exception e){ + logger.error("Error creating composer", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + + } +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/composer/DeleteComposerHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/composer/DeleteComposerHandler.java new file mode 100644 index 0000000..b159427 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/composer/DeleteComposerHandler.java @@ -0,0 +1,53 @@ +package com.mediamanager.service.delegate.handler.composer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.ComposerMessages; +import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action( "composer.delete") +public class DeleteComposerHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(DeleteComposerHandler.class); + private final ComposerService composerService; + + + public DeleteComposerHandler(ComposerService composerService){ + this.composerService = composerService; + } + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + try { + ComposerMessages.DeleteComposerRequest deleteRequest = + ComposerMessages.DeleteComposerRequest.parseFrom(requestPayload); + int id = deleteRequest.getId(); + boolean success = composerService.deleteComposer(id); + ComposerMessages.DeleteComposerResponse deleteResponse; + if(success){ + deleteResponse = ComposerMessages.DeleteComposerResponse.newBuilder().setSuccess(true) + .setMessage("Composer deleted successfully").build(); + + + return TransportProtocol.Response.newBuilder() + .setPayload(deleteResponse.toByteString()); + }else { + deleteResponse = ComposerMessages.DeleteComposerResponse.newBuilder().setSuccess(false) + .setMessage("Composer not found").build(); + return TransportProtocol.Response.newBuilder().setStatusCode(404) + .setPayload(deleteResponse.toByteString()); + } + + } catch (Exception e) { + logger.error("Error deleting composer", e); + ComposerMessages.DeleteComposerResponse deleteResponse = ComposerMessages.DeleteComposerResponse + .newBuilder().setSuccess(false).setMessage("Error: " + e.getMessage()).build(); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500).setPayload(deleteResponse.toByteString()); + } + } +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerByIdHandler.java new file mode 100644 index 0000000..d1336b9 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerByIdHandler.java @@ -0,0 +1,57 @@ +package com.mediamanager.service.delegate.handler.composer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.ComposerMapper; +import com.mediamanager.model.Composer; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.ComposerMessages; +import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +@Action( "composer.getById") +public class GetComposerByIdHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetComposerByIdHandler.class); + private final ComposerService composerService; + + public GetComposerByIdHandler(ComposerService composerService){ + this.composerService = composerService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + try{ + + ComposerMessages.GetComposerByIdRequest getByIdRequest = ComposerMessages.GetComposerByIdRequest + .parseFrom(requestPayload); + int id = getByIdRequest.getId(); + + Optional composerOpt = composerService.getComposerById(id); + + if (composerOpt.isEmpty()) { + logger.warn("Composer not found with ID: {}", id); + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(ByteString.copyFromUtf8("Composer not found")); + } + + ComposerMessages.Composer composerProto = ComposerMapper.toProtobuf(composerOpt.get()); + + ComposerMessages.GetComposerByIdResponse getByIdResponse = ComposerMessages.GetComposerByIdResponse + .newBuilder().setComposer(composerProto).build(); + + return TransportProtocol.Response.newBuilder().setPayload(getByIdResponse.toByteString()); + } catch (Exception e) { + logger.error("Error getting composer by ID", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerHandler.java new file mode 100644 index 0000000..0d41487 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/composer/GetComposerHandler.java @@ -0,0 +1,50 @@ +package com.mediamanager.service.delegate.handler.composer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.ComposerMapper; +import com.mediamanager.model.Composer; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.ComposerMessages; +import com.mediamanager.protocol.messages.GenreMessages; +import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + +@Action( "composer.getAll") +public class GetComposerHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetComposerHandler.class); + private final ComposerService composerService; + + public GetComposerHandler(ComposerService composerService){ + this.composerService = composerService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + + try{ + List composers = composerService.getAllComposers(); + + ComposerMessages.GetComposersResponse.Builder responseBuilder = ComposerMessages.GetComposersResponse.newBuilder(); + for(Composer composer : composers){ + ComposerMessages.Composer composerProto = ComposerMapper.toProtobuf(composer); + responseBuilder.addComposers(composerProto); + } + ComposerMessages.GetComposersResponse getGenresResponse = responseBuilder.build(); + return TransportProtocol.Response.newBuilder().setPayload(getGenresResponse.toByteString()); + } catch (Exception e) { + logger.error("Error getting composers", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + + } + +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/composer/UpdateComposerHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/composer/UpdateComposerHandler.java new file mode 100644 index 0000000..d81af26 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/composer/UpdateComposerHandler.java @@ -0,0 +1,56 @@ +package com.mediamanager.service.delegate.handler.composer; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.ComposerMapper; +import com.mediamanager.model.Composer; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.ComposerMessages; +import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +@Action("composer.update") +public class UpdateComposerHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(UpdateComposerHandler.class); + private final ComposerService composerService; + public UpdateComposerHandler(ComposerService composerService){ + this.composerService = composerService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + try{ + ComposerMessages.UpdateComposerRequest updateRequest = ComposerMessages.UpdateComposerRequest + .parseFrom(requestPayload); + int id = updateRequest.getId(); + String newName = updateRequest.getName(); + Optional composerOpt = composerService.updateComposer(id, newName); + if (composerOpt.isEmpty()) { + logger.warn("Composer not found with ID: {}", id); + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(ByteString.copyFromUtf8("Composer not found")); + } + ComposerMessages.Composer composerProto = ComposerMapper.toProtobuf(composerOpt.get()); + ComposerMessages.UpdateComposerResponse updateResponse = ComposerMessages.UpdateComposerResponse + .newBuilder().setComposer(composerProto).build(); + return TransportProtocol.Response.newBuilder().setPayload(updateResponse.toByteString()); + }catch (IllegalArgumentException e){ + logger.error("Validation error", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(400) + .setPayload(ByteString.copyFromUtf8("Validation error: " + e.getMessage())); + } catch (Exception e) { + logger.error("Error updating composer", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/proto/composer.proto b/src/main/proto/composer.proto new file mode 100644 index 0000000..ce82fba --- /dev/null +++ b/src/main/proto/composer.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +option java_package = "com.mediamanager.protocol.messages"; +option java_outer_classname = "ComposerMessages"; + +package mediamanager.messages; + +message Composer { + int32 id =1; + string name =2; +} + +message CreateComposerRequest{ + string name =1; +} + +message CreateComposerResponse{ + Composer composer = 1; +} + +message GetComposersRequest{} + +message GetComposersResponse{ + repeated Composer composers = 1; +} + +message GetComposerByIdRequest{ + int32 id =1; +} + +message GetComposerByIdResponse{ + Composer composer =1; +} + +message UpdateComposerRequest{ + int32 id = 1; + string name=2; +} + +message UpdateComposerResponse{ + Composer composer = 1; +} + +message DeleteComposerRequest{ + int32 id = 1; +} + +message DeleteComposerResponse{ + bool success = 1; + string message = 2; +}