From e0799828d074d601d0cf6b768ebed5eb8f290ab7 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Tue, 9 Dec 2025 02:24:40 -0300 Subject: [PATCH 1/2] Implement trackhasgenre relationship management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add complete implementation for track-genre relationship management, following the established albumhasgenre pattern. This enables tracking which genres are associated with each track in the media library. Changes: - Fix trackhasgenre.proto: Correct CreateTrackHasGenreRequest to use fk_track_id instead of fk_album_id - Enhance TrackHasGenre model with nullable constraints, constructor, and toString method - Implement TrackHasGenreRepository with full CRUD operations - Implement TrackHasGenreService with business logic and validation - Add TrackHasGenreMapper for entity/protobuf conversion - Create action handlers: * CreateTrackHasGenreHandler (trackhasgenre.create) * DeleteTrackHasGenreHandler (trackhasgenre.delete) * GetTrackHasGenreByIdHandler (trackhasgenre.getById) * GetTrackHasGenreHandler (trackhasgenre.getAll) - Register TrackHasGenreService in DelegateActionManager for automatic handler discovery and dependency injection The implementation validates track and genre existence before creating relationships and provides proper error handling with appropriate HTTP status codes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../mapper/TrackHasGenreMapper.java | 47 ++++++++++ .../com/mediamanager/model/TrackHasGenre.java | 55 ++++++++++++ .../repository/TrackHasGenreRepository.java | 85 +++++++++++++++++++ .../delegate/DelegateActionManager.java | 5 ++ .../CreateTrackHasGenreHandler.java | 54 ++++++++++++ .../DeleteTrackHasGenreHandler.java | 62 ++++++++++++++ .../GetTrackHasGenreByIdHandler.java | 56 ++++++++++++ .../GetTrackHasGenreHandler.java | 48 +++++++++++ .../trackhasgenre/TrackHasGenreService.java | 77 +++++++++++++++++ src/main/proto/trackhasgenre.proto | 46 ++++++++++ 10 files changed, 535 insertions(+) create mode 100644 src/main/java/com/mediamanager/mapper/TrackHasGenreMapper.java create mode 100644 src/main/java/com/mediamanager/model/TrackHasGenre.java create mode 100644 src/main/java/com/mediamanager/repository/TrackHasGenreRepository.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/CreateTrackHasGenreHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/DeleteTrackHasGenreHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreByIdHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreHandler.java create mode 100644 src/main/java/com/mediamanager/service/trackhasgenre/TrackHasGenreService.java create mode 100644 src/main/proto/trackhasgenre.proto diff --git a/src/main/java/com/mediamanager/mapper/TrackHasGenreMapper.java b/src/main/java/com/mediamanager/mapper/TrackHasGenreMapper.java new file mode 100644 index 0000000..e3e6968 --- /dev/null +++ b/src/main/java/com/mediamanager/mapper/TrackHasGenreMapper.java @@ -0,0 +1,47 @@ +package com.mediamanager.mapper; + +import com.mediamanager.model.TrackHasGenre; +import com.mediamanager.protocol.messages.TrackHasGenreMessages; + +public class TrackHasGenreMapper { + public static TrackHasGenreMessages.TrackHasGenre toProtobuf(TrackHasGenre entity) { + if (entity == null) { + return null; + } + + TrackHasGenreMessages.TrackHasGenre.Builder builder = TrackHasGenreMessages.TrackHasGenre.newBuilder(); + + Integer id = entity.getId(); + if (id != null) { + builder.setId(id); + } + + // Map Track foreign key + if (entity.getTrack() != null && entity.getTrack().getId() != null) { + builder.setFkTrackId(entity.getTrack().getId()); + } + + // Map Genre foreign key + if (entity.getGenre() != null && entity.getGenre().getId() != null) { + builder.setFkGenreId(entity.getGenre().getId()); + } + + return builder.build(); + } + + public static TrackHasGenre toEntity(TrackHasGenreMessages.TrackHasGenre protobuf) { + if (protobuf == null) { + return null; + } + + TrackHasGenre entity = new TrackHasGenre(); + + if (protobuf.getId() > 0) { + entity.setId(protobuf.getId()); + } + + // Note: Foreign key relationships (Track, Genre) are handled in the service layer + + return entity; + } +} diff --git a/src/main/java/com/mediamanager/model/TrackHasGenre.java b/src/main/java/com/mediamanager/model/TrackHasGenre.java new file mode 100644 index 0000000..e2e6717 --- /dev/null +++ b/src/main/java/com/mediamanager/model/TrackHasGenre.java @@ -0,0 +1,55 @@ +package com.mediamanager.model; + +import jakarta.persistence.*; + +@Entity +@Table(name = "trackhasgenre") +public class TrackHasGenre { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "fk_track_id", nullable = false) + private Track track; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "fk_genre_id", nullable = false) + private Genre genre; + + public TrackHasGenre() {} + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Track getTrack() { + return track; + } + + public void setTrack(Track track) { + this.track = track; + } + + public Genre getGenre() { + return genre; + } + + public void setGenre(Genre genre) { + this.genre = genre; + } + + @Override + public String toString() { + return "TrackHasGenre{" + + "id=" + id + + ", trackId=" + (track != null ? track.getId() : null) + + ", genreId=" + (genre != null ? genre.getId() : null) + + '}'; + } +} diff --git a/src/main/java/com/mediamanager/repository/TrackHasGenreRepository.java b/src/main/java/com/mediamanager/repository/TrackHasGenreRepository.java new file mode 100644 index 0000000..6437e04 --- /dev/null +++ b/src/main/java/com/mediamanager/repository/TrackHasGenreRepository.java @@ -0,0 +1,85 @@ +package com.mediamanager.repository; + + +import com.mediamanager.model.TrackHasGenre; +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 TrackHasGenreRepository { + private static final Logger logger = LogManager.getLogger(TrackHasGenreRepository.class); + + private final EntityManagerFactory entityManagerFactory; + + public TrackHasGenreRepository(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + } + + public TrackHasGenre save(TrackHasGenre trackHasGenre) { + logger.debug("Saving TrackHasGenre: {}", trackHasGenre); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try { + em.persist(trackHasGenre); + em.getTransaction().commit(); + logger.debug("TrackHasGenre has been saved successfully"); + return trackHasGenre; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error while saving TrackHasGenre: {}", e.getMessage()); + throw e; + } finally { + if (em.isOpen()) em.close(); + } + } + + public List findAll() { + logger.debug("Finding All TrackHasGenre"); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + return em.createQuery("select t from TrackHasGenre t", TrackHasGenre.class).getResultList(); + }finally { + if (em.isOpen()) em.close(); + } + } + + public Optional findById(Integer id) { + logger.debug("Finding TrackHasGenre with id: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + TrackHasGenre trackHasGenre = em.find(TrackHasGenre.class, id); + return Optional.ofNullable(trackHasGenre); + }finally { + if (em.isOpen()) em.close(); + } + } + + public boolean deleteById(Integer id){ + logger.debug("Deleting TrackHasGenre with id: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try{ + TrackHasGenre trackHasGenre = em.find(TrackHasGenre.class, id); + if (trackHasGenre == null) { + em.getTransaction().rollback(); + return false; + } + em.remove(trackHasGenre); + em.getTransaction().commit(); + logger.debug("TrackHasGenre has been deleted successfully"); + return true; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error while deleting TrackHasGenre: {}", e.getMessage()); + throw e; + } finally { + if (em.isOpen()) em.close(); + } + } + +} diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index 11c3354..da043f5 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -12,6 +12,7 @@ import com.mediamanager.service.albumtype.AlbumTypeService; import com.mediamanager.service.bitdepth.BitDepthService; import com.mediamanager.service.bitrate.BitRateService; import com.mediamanager.service.composer.ComposerService; +import com.mediamanager.service.trackhasgenre.TrackHasGenreService; import com.mediamanager.repository.GenreRepository; import com.mediamanager.service.artist.ArtistService; @@ -112,6 +113,10 @@ public class DelegateActionManager { TrackService trackService = new TrackService(trackRepository, discRepository, composerRepository, bitDepthRepository, bitRateRepository, samplingRateRepository); serviceLocator.register(TrackService.class, trackService); + TrackHasGenreRepository trackHasGenreRepository = new TrackHasGenreRepository(entityManagerFactory); + TrackHasGenreService trackHasGenreService = new TrackHasGenreService(trackHasGenreRepository, trackRepository, genreRepository); + serviceLocator.register(TrackHasGenreService.class, trackHasGenreService); + serviceLocator.logRegisteredServices(); logger.info("Services initialized successfully"); diff --git a/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/CreateTrackHasGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/CreateTrackHasGenreHandler.java new file mode 100644 index 0000000..e8b9d09 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/CreateTrackHasGenreHandler.java @@ -0,0 +1,54 @@ +package com.mediamanager.service.delegate.handler.trackhasgenre; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasGenreMapper; +import com.mediamanager.model.TrackHasGenre; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasGenreMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasgenre.TrackHasGenreService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action("trackhasgenre.create") +public class CreateTrackHasGenreHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(CreateTrackHasGenreHandler.class); + private final TrackHasGenreService trackHasGenreService; + + public CreateTrackHasGenreHandler(TrackHasGenreService trackHasGenreService) { + this.trackHasGenreService = trackHasGenreService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException { + try{ + TrackHasGenreMessages.CreateTrackHasGenreRequest createRequest = + TrackHasGenreMessages.CreateTrackHasGenreRequest.parseFrom(requestPayload); + + TrackHasGenre trackHasGenre = trackHasGenreService.createTrackHasGenre( + createRequest.getFkTrackId() > 0 ? createRequest.getFkTrackId() : null, + createRequest.getFkGenreId() > 0 ? createRequest.getFkGenreId() : null + ); + + TrackHasGenreMessages.TrackHasGenre trackHasGenreProto = TrackHasGenreMapper.toProtobuf(trackHasGenre); + TrackHasGenreMessages.CreateTrackHasGenreResponse createTrackHasGenreResponse = TrackHasGenreMessages.CreateTrackHasGenreResponse.newBuilder() + .setTrackhasgenre(trackHasGenreProto) + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(createTrackHasGenreResponse.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 track has genre", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/DeleteTrackHasGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/DeleteTrackHasGenreHandler.java new file mode 100644 index 0000000..17c01de --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/DeleteTrackHasGenreHandler.java @@ -0,0 +1,62 @@ +package com.mediamanager.service.delegate.handler.trackhasgenre; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasGenreMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasgenre.TrackHasGenreService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action("trackhasgenre.delete") +public class DeleteTrackHasGenreHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(DeleteTrackHasGenreHandler.class); + + private final TrackHasGenreService trackHasGenreService; + + public DeleteTrackHasGenreHandler(TrackHasGenreService trackHasGenreService) { + this.trackHasGenreService = trackHasGenreService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + + try { + TrackHasGenreMessages.DeleteTrackHasGenreRequest deleteRequest = + TrackHasGenreMessages.DeleteTrackHasGenreRequest.parseFrom(requestPayload); + int id = deleteRequest.getId(); + boolean success = trackHasGenreService.deleteTrackHasGenre(id); + TrackHasGenreMessages.DeleteTrackHasGenreResponse deleteResponse; + if (success) { + deleteResponse = TrackHasGenreMessages.DeleteTrackHasGenreResponse.newBuilder() + .setSuccess(true) + .setMessage("Track has genre deleted successfully") + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(deleteResponse.toByteString()); + } else { + deleteResponse = TrackHasGenreMessages.DeleteTrackHasGenreResponse.newBuilder() + .setSuccess(false) + .setMessage("Track has genre not found") + .build(); + + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(deleteResponse.toByteString()); + } + } catch (Exception e) { + logger.error("Error deleting track has genre", e); + TrackHasGenreMessages.DeleteTrackHasGenreResponse deleteResponse = + TrackHasGenreMessages.DeleteTrackHasGenreResponse.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/trackhasgenre/GetTrackHasGenreByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreByIdHandler.java new file mode 100644 index 0000000..6a0c5d6 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreByIdHandler.java @@ -0,0 +1,56 @@ +package com.mediamanager.service.delegate.handler.trackhasgenre; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasGenreMapper; +import com.mediamanager.model.TrackHasGenre; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasGenreMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasgenre.TrackHasGenreService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +@Action(value = "trackhasgenre.getById") +public class GetTrackHasGenreByIdHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetTrackHasGenreByIdHandler.class); + private final TrackHasGenreService trackHasGenreService; + + public GetTrackHasGenreByIdHandler(TrackHasGenreService trackHasGenreService) { + this.trackHasGenreService = trackHasGenreService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException{ + + try{ + TrackHasGenreMessages.GetTrackHasGenreByIdRequest getByIdRequest = + TrackHasGenreMessages.GetTrackHasGenreByIdRequest.parseFrom(requestPayload); + int id = getByIdRequest.getId(); + + Optional trackHasGenreOpt = trackHasGenreService.getTrackHasGenreById(id); + + if (trackHasGenreOpt.isEmpty()){ + logger.warn("TrackHasGenre not found with ID: {}", id); + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(ByteString.copyFromUtf8("TrackHasGenre not found")); + } + TrackHasGenreMessages.TrackHasGenre trackHasGenreProto = TrackHasGenreMapper.toProtobuf(trackHasGenreOpt.get()); + TrackHasGenreMessages.GetTrackHasGenreByIdResponse getByIdResponse = TrackHasGenreMessages.GetTrackHasGenreByIdResponse.newBuilder() + .setTrackhasgenre(trackHasGenreProto) + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(getByIdResponse.toByteString()); + } catch (Exception e) { + logger.error("Error getting track has genre 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/trackhasgenre/GetTrackHasGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreHandler.java new file mode 100644 index 0000000..35b43f5 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasgenre/GetTrackHasGenreHandler.java @@ -0,0 +1,48 @@ +package com.mediamanager.service.delegate.handler.trackhasgenre; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasGenreMapper; +import com.mediamanager.model.TrackHasGenre; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasGenreMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasgenre.TrackHasGenreService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + + +@Action("trackhasgenre.getAll") +public class GetTrackHasGenreHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetTrackHasGenreHandler.class); + + private final TrackHasGenreService trackHasGenreService; + + public GetTrackHasGenreHandler(TrackHasGenreService trackHasGenreService){this.trackHasGenreService = trackHasGenreService;} + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException { + try{ + List trackHasGenres = trackHasGenreService.getAllTrackHasGenres(); + TrackHasGenreMessages.GetTrackHasGenresResponse.Builder responseBuilder = TrackHasGenreMessages.GetTrackHasGenresResponse.newBuilder(); + + for (TrackHasGenre trackHasGenre : trackHasGenres) { + TrackHasGenreMessages.TrackHasGenre trackHasGenreProto = TrackHasGenreMapper.toProtobuf(trackHasGenre); + responseBuilder.addTrackhasgenre(trackHasGenreProto); + } + TrackHasGenreMessages.GetTrackHasGenresResponse getTrackHasGenresResponse = responseBuilder.build(); + + return TransportProtocol.Response.newBuilder() + .setPayload(getTrackHasGenresResponse.toByteString()); + + }catch (Exception e){ + logger.error("Error getting track has genres", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/java/com/mediamanager/service/trackhasgenre/TrackHasGenreService.java b/src/main/java/com/mediamanager/service/trackhasgenre/TrackHasGenreService.java new file mode 100644 index 0000000..82b97f3 --- /dev/null +++ b/src/main/java/com/mediamanager/service/trackhasgenre/TrackHasGenreService.java @@ -0,0 +1,77 @@ +package com.mediamanager.service.trackhasgenre; + +import com.mediamanager.model.Track; +import com.mediamanager.model.TrackHasGenre; +import com.mediamanager.model.Genre; +import com.mediamanager.repository.TrackHasGenreRepository; +import com.mediamanager.repository.TrackRepository; +import com.mediamanager.repository.GenreRepository; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class TrackHasGenreService { + private static final Logger logger = LogManager.getLogger(TrackHasGenreService.class); + private final TrackHasGenreRepository repository; + private final TrackRepository trackRepository; + private final GenreRepository genreRepository; + + public TrackHasGenreService(TrackHasGenreRepository repository, TrackRepository trackRepository, GenreRepository genreRepository) { + this.repository = repository; + this.trackRepository = trackRepository; + this.genreRepository = genreRepository; + } + + public TrackHasGenre createTrackHasGenre(Integer trackId, Integer genreId) { + logger.debug("Creating track has genre relationship - trackId:{}, genreId:{}", trackId, genreId); + + if (trackId == null || trackId <= 0) { + throw new IllegalArgumentException("Track ID cannot be null or invalid"); + } + if (genreId == null || genreId <= 0) { + throw new IllegalArgumentException("Genre ID cannot be null or invalid"); + } + + // Verify Track exists + Optional track = trackRepository.findById(trackId); + if (track.isEmpty()) { + throw new IllegalArgumentException("Track not found with id: " + trackId); + } + + // Verify Genre exists + Optional genre = genreRepository.findById(genreId); + if (genre.isEmpty()) { + throw new IllegalArgumentException("Genre not found with id: " + genreId); + } + + TrackHasGenre trackHasGenre = new TrackHasGenre(); + trackHasGenre.setTrack(track.get()); + trackHasGenre.setGenre(genre.get()); + + return repository.save(trackHasGenre); + } + + public List getAllTrackHasGenres() { + logger.info("Getting all track has genre relationships"); + return repository.findAll(); + } + + public Optional getTrackHasGenreById(Integer id) { + if (id == null) { + throw new IllegalArgumentException("ID cannot be null"); + } + logger.info("Getting track has genre by id:{}", id); + return repository.findById(id); + } + + public boolean deleteTrackHasGenre(Integer id) { + if (id == null) { + throw new IllegalArgumentException("Track has genre id cannot be null"); + } + logger.info("Deleting track has genre:{}", id); + return repository.deleteById(id); + } + +} diff --git a/src/main/proto/trackhasgenre.proto b/src/main/proto/trackhasgenre.proto new file mode 100644 index 0000000..e483697 --- /dev/null +++ b/src/main/proto/trackhasgenre.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; + +option java_package = "com.mediamanager.protocol.messages"; +option java_outer_classname = "TrackHasGenreMessages"; + +package mediamanager.messages; + +message TrackHasGenre{ + int32 id = 1; + int32 fk_track_id = 2; + int32 fk_genre_id =3; +} + +message CreateTrackHasGenreRequest { + int32 fk_track_id = 1; + int32 fk_genre_id = 2; +} + +message CreateTrackHasGenreResponse { + TrackHasGenre trackhasgenre = 1; +} + +message GetTrackHasGenresRequest { + +} + +message GetTrackHasGenresResponse { + repeated TrackHasGenre trackhasgenre = 1; +} + +message GetTrackHasGenreByIdRequest { + int32 id = 1; +} + +message GetTrackHasGenreByIdResponse { + TrackHasGenre trackhasgenre = 1; +} + +message DeleteTrackHasGenreRequest { + int32 id = 1; +} + +message DeleteTrackHasGenreResponse { + bool success = 1; + string message = 2; +} \ No newline at end of file From 7fd3c3e9f78da8b9ccc8a4e225478eb31be674c0 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Tue, 9 Dec 2025 02:44:57 -0300 Subject: [PATCH 2/2] Implement trackhasartist relationship management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add complete implementation for track-artist relationship management, following the established albumhasgenre pattern. This enables tracking which artists are associated with each track in the media library. Changes: - Fix TrackHasArtist model: Rename from TrackHasArtistt.java (typo) and correct table name from "trackhasgenre" to "trackhasartist" - Implement TrackHasArtistRepository with full CRUD operations - Implement TrackHasArtistService with business logic and validation - Add TrackHasArtistMapper for entity/protobuf conversion - Create action handlers: * CreateTrackHasArtistHandler (trackhasartist.create) * DeleteTrackHasArtistHandler (trackhasartist.delete) * GetTrackHasArtistByIdHandler (trackhasartist.getById) * GetTrackHasArtistHandler (trackhasartist.getAll) - Register TrackHasArtistService in DelegateActionManager for automatic handler discovery and dependency injection - Proto file (trackhasartist.proto) was already correct The implementation validates track and artist existence before creating relationships and provides proper error handling with appropriate HTTP status codes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../mapper/TrackHasArtistMapper.java | 47 ++++++++++ .../mediamanager/model/TrackHasArtist.java | 55 ++++++++++++ .../repository/TrackHasArtistRepository.java | 85 +++++++++++++++++++ .../delegate/DelegateActionManager.java | 5 ++ .../CreateTrackHasArtistHandler.java | 54 ++++++++++++ .../DeleteTrackHasArtistHandler.java | 62 ++++++++++++++ .../GetTrackHasArtistByIdHandler.java | 56 ++++++++++++ .../GetTrackHasArtistHandler.java | 48 +++++++++++ .../trackhasartist/TrackHasArtistService.java | 77 +++++++++++++++++ src/main/proto/trackhasartist.proto | 46 ++++++++++ 10 files changed, 535 insertions(+) create mode 100644 src/main/java/com/mediamanager/mapper/TrackHasArtistMapper.java create mode 100644 src/main/java/com/mediamanager/model/TrackHasArtist.java create mode 100644 src/main/java/com/mediamanager/repository/TrackHasArtistRepository.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/CreateTrackHasArtistHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/DeleteTrackHasArtistHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistByIdHandler.java create mode 100644 src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistHandler.java create mode 100644 src/main/java/com/mediamanager/service/trackhasartist/TrackHasArtistService.java create mode 100644 src/main/proto/trackhasartist.proto diff --git a/src/main/java/com/mediamanager/mapper/TrackHasArtistMapper.java b/src/main/java/com/mediamanager/mapper/TrackHasArtistMapper.java new file mode 100644 index 0000000..f8a0d20 --- /dev/null +++ b/src/main/java/com/mediamanager/mapper/TrackHasArtistMapper.java @@ -0,0 +1,47 @@ +package com.mediamanager.mapper; + +import com.mediamanager.model.TrackHasArtist; +import com.mediamanager.protocol.messages.TrackHasArtistMessages; + +public class TrackHasArtistMapper { + public static TrackHasArtistMessages.TrackHasArtist toProtobuf(TrackHasArtist entity) { + if (entity == null) { + return null; + } + + TrackHasArtistMessages.TrackHasArtist.Builder builder = TrackHasArtistMessages.TrackHasArtist.newBuilder(); + + Integer id = entity.getId(); + if (id != null) { + builder.setId(id); + } + + // Map Track foreign key + if (entity.getTrack() != null && entity.getTrack().getId() != null) { + builder.setFkTrackId(entity.getTrack().getId()); + } + + // Map Artist foreign key + if (entity.getArtist() != null && entity.getArtist().getId() != null) { + builder.setFkArtistId(entity.getArtist().getId()); + } + + return builder.build(); + } + + public static TrackHasArtist toEntity(TrackHasArtistMessages.TrackHasArtist protobuf) { + if (protobuf == null) { + return null; + } + + TrackHasArtist entity = new TrackHasArtist(); + + if (protobuf.getId() > 0) { + entity.setId(protobuf.getId()); + } + + // Note: Foreign key relationships (Track, Artist) are handled in the service layer + + return entity; + } +} diff --git a/src/main/java/com/mediamanager/model/TrackHasArtist.java b/src/main/java/com/mediamanager/model/TrackHasArtist.java new file mode 100644 index 0000000..abba89e --- /dev/null +++ b/src/main/java/com/mediamanager/model/TrackHasArtist.java @@ -0,0 +1,55 @@ +package com.mediamanager.model; + +import jakarta.persistence.*; + +@Entity +@Table(name = "trackhasartist") +public class TrackHasArtist { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "fk_track_id", nullable = false) + private Track track; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "fk_artist_id", nullable = false) + private Artist artist; + + public TrackHasArtist() {} + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Track getTrack() { + return track; + } + + public void setTrack(Track track) { + this.track = track; + } + + public Artist getArtist() { + return artist; + } + + public void setArtist(Artist artist) { + this.artist = artist; + } + + @Override + public String toString() { + return "TrackHasArtist{" + + "id=" + id + + ", trackId=" + (track != null ? track.getId() : null) + + ", artistId=" + (artist != null ? artist.getId() : null) + + '}'; + } +} diff --git a/src/main/java/com/mediamanager/repository/TrackHasArtistRepository.java b/src/main/java/com/mediamanager/repository/TrackHasArtistRepository.java new file mode 100644 index 0000000..1d81f37 --- /dev/null +++ b/src/main/java/com/mediamanager/repository/TrackHasArtistRepository.java @@ -0,0 +1,85 @@ +package com.mediamanager.repository; + + +import com.mediamanager.model.TrackHasArtist; +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 TrackHasArtistRepository { + private static final Logger logger = LogManager.getLogger(TrackHasArtistRepository.class); + + private final EntityManagerFactory entityManagerFactory; + + public TrackHasArtistRepository(EntityManagerFactory entityManagerFactory) { + this.entityManagerFactory = entityManagerFactory; + } + + public TrackHasArtist save(TrackHasArtist trackHasArtist) { + logger.debug("Saving TrackHasArtist: {}", trackHasArtist); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try { + em.persist(trackHasArtist); + em.getTransaction().commit(); + logger.debug("TrackHasArtist has been saved successfully"); + return trackHasArtist; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error while saving TrackHasArtist: {}", e.getMessage()); + throw e; + } finally { + if (em.isOpen()) em.close(); + } + } + + public List findAll() { + logger.debug("Finding All TrackHasArtist"); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + return em.createQuery("select t from TrackHasArtist t", TrackHasArtist.class).getResultList(); + }finally { + if (em.isOpen()) em.close(); + } + } + + public Optional findById(Integer id) { + logger.debug("Finding TrackHasArtist with id: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + try{ + TrackHasArtist trackHasArtist = em.find(TrackHasArtist.class, id); + return Optional.ofNullable(trackHasArtist); + }finally { + if (em.isOpen()) em.close(); + } + } + + public boolean deleteById(Integer id){ + logger.debug("Deleting TrackHasArtist with id: {}", id); + EntityManager em = entityManagerFactory.createEntityManager(); + em.getTransaction().begin(); + try{ + TrackHasArtist trackHasArtist = em.find(TrackHasArtist.class, id); + if (trackHasArtist == null) { + em.getTransaction().rollback(); + return false; + } + em.remove(trackHasArtist); + em.getTransaction().commit(); + logger.debug("TrackHasArtist has been deleted successfully"); + return true; + } catch (Exception e) { + em.getTransaction().rollback(); + logger.error("Error while deleting TrackHasArtist: {}", e.getMessage()); + throw e; + } finally { + if (em.isOpen()) em.close(); + } + } + +} diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index da043f5..724c87d 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -13,6 +13,7 @@ import com.mediamanager.service.bitdepth.BitDepthService; import com.mediamanager.service.bitrate.BitRateService; import com.mediamanager.service.composer.ComposerService; import com.mediamanager.service.trackhasgenre.TrackHasGenreService; +import com.mediamanager.service.trackhasartist.TrackHasArtistService; import com.mediamanager.repository.GenreRepository; import com.mediamanager.service.artist.ArtistService; @@ -117,6 +118,10 @@ public class DelegateActionManager { TrackHasGenreService trackHasGenreService = new TrackHasGenreService(trackHasGenreRepository, trackRepository, genreRepository); serviceLocator.register(TrackHasGenreService.class, trackHasGenreService); + TrackHasArtistRepository trackHasArtistRepository = new TrackHasArtistRepository(entityManagerFactory); + TrackHasArtistService trackHasArtistService = new TrackHasArtistService(trackHasArtistRepository, trackRepository, artistRepository); + serviceLocator.register(TrackHasArtistService.class, trackHasArtistService); + serviceLocator.logRegisteredServices(); logger.info("Services initialized successfully"); diff --git a/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/CreateTrackHasArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/CreateTrackHasArtistHandler.java new file mode 100644 index 0000000..37af6c3 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/CreateTrackHasArtistHandler.java @@ -0,0 +1,54 @@ +package com.mediamanager.service.delegate.handler.trackhasartist; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasArtistMapper; +import com.mediamanager.model.TrackHasArtist; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasArtistMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasartist.TrackHasArtistService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action("trackhasartist.create") +public class CreateTrackHasArtistHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(CreateTrackHasArtistHandler.class); + private final TrackHasArtistService trackHasArtistService; + + public CreateTrackHasArtistHandler(TrackHasArtistService trackHasArtistService) { + this.trackHasArtistService = trackHasArtistService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException { + try{ + TrackHasArtistMessages.CreateTrackHasArtistRequest createRequest = + TrackHasArtistMessages.CreateTrackHasArtistRequest.parseFrom(requestPayload); + + TrackHasArtist trackHasArtist = trackHasArtistService.createTrackHasArtist( + createRequest.getFkTrackId() > 0 ? createRequest.getFkTrackId() : null, + createRequest.getFkArtistId() > 0 ? createRequest.getFkArtistId() : null + ); + + TrackHasArtistMessages.TrackHasArtist trackHasArtistProto = TrackHasArtistMapper.toProtobuf(trackHasArtist); + TrackHasArtistMessages.CreateTrackHasArtistResponse createTrackHasArtistResponse = TrackHasArtistMessages.CreateTrackHasArtistResponse.newBuilder() + .setTrackhasartist(trackHasArtistProto) + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(createTrackHasArtistResponse.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 track has artist", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/DeleteTrackHasArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/DeleteTrackHasArtistHandler.java new file mode 100644 index 0000000..1b7c643 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/DeleteTrackHasArtistHandler.java @@ -0,0 +1,62 @@ +package com.mediamanager.service.delegate.handler.trackhasartist; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasArtistMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasartist.TrackHasArtistService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Action("trackhasartist.delete") +public class DeleteTrackHasArtistHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(DeleteTrackHasArtistHandler.class); + + private final TrackHasArtistService trackHasArtistService; + + public DeleteTrackHasArtistHandler(TrackHasArtistService trackHasArtistService) { + this.trackHasArtistService = trackHasArtistService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException { + + try { + TrackHasArtistMessages.DeleteTrackHasArtistRequest deleteRequest = + TrackHasArtistMessages.DeleteTrackHasArtistRequest.parseFrom(requestPayload); + int id = deleteRequest.getId(); + boolean success = trackHasArtistService.deleteTrackHasArtist(id); + TrackHasArtistMessages.DeleteTrackHasArtistResponse deleteResponse; + if (success) { + deleteResponse = TrackHasArtistMessages.DeleteTrackHasArtistResponse.newBuilder() + .setSuccess(true) + .setMessage("Track has artist deleted successfully") + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(deleteResponse.toByteString()); + } else { + deleteResponse = TrackHasArtistMessages.DeleteTrackHasArtistResponse.newBuilder() + .setSuccess(false) + .setMessage("Track has artist not found") + .build(); + + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(deleteResponse.toByteString()); + } + } catch (Exception e) { + logger.error("Error deleting track has artist", e); + TrackHasArtistMessages.DeleteTrackHasArtistResponse deleteResponse = + TrackHasArtistMessages.DeleteTrackHasArtistResponse.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/trackhasartist/GetTrackHasArtistByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistByIdHandler.java new file mode 100644 index 0000000..db3996f --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistByIdHandler.java @@ -0,0 +1,56 @@ +package com.mediamanager.service.delegate.handler.trackhasartist; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasArtistMapper; +import com.mediamanager.model.TrackHasArtist; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasArtistMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasartist.TrackHasArtistService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Optional; + +@Action(value = "trackhasartist.getById") +public class GetTrackHasArtistByIdHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetTrackHasArtistByIdHandler.class); + private final TrackHasArtistService trackHasArtistService; + + public GetTrackHasArtistByIdHandler(TrackHasArtistService trackHasArtistService) { + this.trackHasArtistService = trackHasArtistService; + } + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) + throws InvalidProtocolBufferException{ + + try{ + TrackHasArtistMessages.GetTrackHasArtistByIdRequest getByIdRequest = + TrackHasArtistMessages.GetTrackHasArtistByIdRequest.parseFrom(requestPayload); + int id = getByIdRequest.getId(); + + Optional trackHasArtistOpt = trackHasArtistService.getTrackHasArtistById(id); + + if (trackHasArtistOpt.isEmpty()){ + logger.warn("TrackHasArtist not found with ID: {}", id); + return TransportProtocol.Response.newBuilder() + .setStatusCode(404) + .setPayload(ByteString.copyFromUtf8("TrackHasArtist not found")); + } + TrackHasArtistMessages.TrackHasArtist trackHasArtistProto = TrackHasArtistMapper.toProtobuf(trackHasArtistOpt.get()); + TrackHasArtistMessages.GetTrackHasArtistByIdResponse getByIdResponse = TrackHasArtistMessages.GetTrackHasArtistByIdResponse.newBuilder() + .setTrackhasartist(trackHasArtistProto) + .build(); + return TransportProtocol.Response.newBuilder() + .setPayload(getByIdResponse.toByteString()); + } catch (Exception e) { + logger.error("Error getting track has artist 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/trackhasartist/GetTrackHasArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistHandler.java new file mode 100644 index 0000000..1734264 --- /dev/null +++ b/src/main/java/com/mediamanager/service/delegate/handler/trackhasartist/GetTrackHasArtistHandler.java @@ -0,0 +1,48 @@ +package com.mediamanager.service.delegate.handler.trackhasartist; + +import com.google.protobuf.ByteString; +import com.google.protobuf.InvalidProtocolBufferException; +import com.mediamanager.mapper.TrackHasArtistMapper; +import com.mediamanager.model.TrackHasArtist; +import com.mediamanager.protocol.TransportProtocol; +import com.mediamanager.protocol.messages.TrackHasArtistMessages; +import com.mediamanager.service.delegate.ActionHandler; +import com.mediamanager.service.delegate.annotation.Action; +import com.mediamanager.service.trackhasartist.TrackHasArtistService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; + + +@Action("trackhasartist.getAll") +public class GetTrackHasArtistHandler implements ActionHandler { + private static final Logger logger = LogManager.getLogger(GetTrackHasArtistHandler.class); + + private final TrackHasArtistService trackHasArtistService; + + public GetTrackHasArtistHandler(TrackHasArtistService trackHasArtistService){this.trackHasArtistService = trackHasArtistService;} + + @Override + public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException { + try{ + List trackHasArtists = trackHasArtistService.getAllTrackHasArtists(); + TrackHasArtistMessages.GetTrackHasArtistsResponse.Builder responseBuilder = TrackHasArtistMessages.GetTrackHasArtistsResponse.newBuilder(); + + for (TrackHasArtist trackHasArtist : trackHasArtists) { + TrackHasArtistMessages.TrackHasArtist trackHasArtistProto = TrackHasArtistMapper.toProtobuf(trackHasArtist); + responseBuilder.addTrackhasartist(trackHasArtistProto); + } + TrackHasArtistMessages.GetTrackHasArtistsResponse getTrackHasArtistsResponse = responseBuilder.build(); + + return TransportProtocol.Response.newBuilder() + .setPayload(getTrackHasArtistsResponse.toByteString()); + + }catch (Exception e){ + logger.error("Error getting track has artists", e); + return TransportProtocol.Response.newBuilder() + .setStatusCode(500) + .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage())); + } + } +} diff --git a/src/main/java/com/mediamanager/service/trackhasartist/TrackHasArtistService.java b/src/main/java/com/mediamanager/service/trackhasartist/TrackHasArtistService.java new file mode 100644 index 0000000..bad7a27 --- /dev/null +++ b/src/main/java/com/mediamanager/service/trackhasartist/TrackHasArtistService.java @@ -0,0 +1,77 @@ +package com.mediamanager.service.trackhasartist; + +import com.mediamanager.model.Track; +import com.mediamanager.model.TrackHasArtist; +import com.mediamanager.model.Artist; +import com.mediamanager.repository.TrackHasArtistRepository; +import com.mediamanager.repository.TrackRepository; +import com.mediamanager.repository.ArtistRepository; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.List; +import java.util.Optional; + +public class TrackHasArtistService { + private static final Logger logger = LogManager.getLogger(TrackHasArtistService.class); + private final TrackHasArtistRepository repository; + private final TrackRepository trackRepository; + private final ArtistRepository artistRepository; + + public TrackHasArtistService(TrackHasArtistRepository repository, TrackRepository trackRepository, ArtistRepository artistRepository) { + this.repository = repository; + this.trackRepository = trackRepository; + this.artistRepository = artistRepository; + } + + public TrackHasArtist createTrackHasArtist(Integer trackId, Integer artistId) { + logger.debug("Creating track has artist relationship - trackId:{}, artistId:{}", trackId, artistId); + + if (trackId == null || trackId <= 0) { + throw new IllegalArgumentException("Track ID cannot be null or invalid"); + } + if (artistId == null || artistId <= 0) { + throw new IllegalArgumentException("Artist ID cannot be null or invalid"); + } + + // Verify Track exists + Optional track = trackRepository.findById(trackId); + if (track.isEmpty()) { + throw new IllegalArgumentException("Track not found with id: " + trackId); + } + + // Verify Artist exists + Optional artist = artistRepository.findById(artistId); + if (artist.isEmpty()) { + throw new IllegalArgumentException("Artist not found with id: " + artistId); + } + + TrackHasArtist trackHasArtist = new TrackHasArtist(); + trackHasArtist.setTrack(track.get()); + trackHasArtist.setArtist(artist.get()); + + return repository.save(trackHasArtist); + } + + public List getAllTrackHasArtists() { + logger.info("Getting all track has artist relationships"); + return repository.findAll(); + } + + public Optional getTrackHasArtistById(Integer id) { + if (id == null) { + throw new IllegalArgumentException("ID cannot be null"); + } + logger.info("Getting track has artist by id:{}", id); + return repository.findById(id); + } + + public boolean deleteTrackHasArtist(Integer id) { + if (id == null) { + throw new IllegalArgumentException("Track has artist id cannot be null"); + } + logger.info("Deleting track has artist:{}", id); + return repository.deleteById(id); + } + +} diff --git a/src/main/proto/trackhasartist.proto b/src/main/proto/trackhasartist.proto new file mode 100644 index 0000000..42b8621 --- /dev/null +++ b/src/main/proto/trackhasartist.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; + +option java_package = "com.mediamanager.protocol.messages"; +option java_outer_classname = "TrackHasArtistMessages"; + +package mediamanager.messages; + +message TrackHasArtist{ + int32 id = 1; + int32 fk_track_id = 2; + int32 fk_artist_id =3; +} + +message CreateTrackHasArtistRequest { + int32 fk_track_id = 1; + int32 fk_artist_id = 2; +} + +message CreateTrackHasArtistResponse { + TrackHasArtist trackhasartist = 1; +} + +message GetTrackHasArtistsRequest { + +} + +message GetTrackHasArtistsResponse { + repeated TrackHasArtist trackhasartist = 1; +} + +message GetTrackHasArtistByIdRequest { + int32 id = 1; +} + +message GetTrackHasArtistByIdResponse { + TrackHasArtist trackhasartist = 1; +} + +message DeleteTrackHasArtistRequest { + int32 id = 1; +} + +message DeleteTrackHasArtistResponse { + bool success = 1; + string message = 2; +} \ No newline at end of file