Compare commits

..

5 Commits

Author SHA1 Message Date
Gustavo Henrique Miranda 1dd2542656
Merge pull request #19 from gmbrax/fix/Fix-artist-proto-mismatch
Feature/Implement-BitRate-Management
2025-12-05 21:55:31 -03:00
Gustavo Henrique Santos Souza de Miranda c787eba20e Fix field name casing in UpdateArtistResponse proto message
Change field name from 'Artist' to 'artist' to follow protobuf naming conventions, which require lowercase field names with underscores for word separation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-05 21:48:46 -03:00
Gustavo Henrique Santos Souza de Miranda 2294a57ffd Implement bit-rate management feature
Add complete CRUD functionality for bit-rate management following the same pattern as bit-depth:
  - Create BitRate entity model with JPA annotations
  - Implement BitRateRepository with full CRUD operations
  - Add BitRateService with validation and business logic
  - Create BitRateMapper for protobuf/entity conversion
  - Implement action handlers: Create, GetAll, GetById, Update, Delete
  - Define bitrate.proto protobuf message definitions
  - Register BitRateService in DelegateActionManager

  🤖 Generated with [Claude Code](https://claude.com/claude-code)

  Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 20:43:04 -03:00
Gustavo Henrique Miranda 8c8b8ec765
Merge pull request #17 from gmbrax/fix/Fix-Repeated-return-on-CreateBitDepthHandler
Remove duplicate `newBuilder` call in `CreateBitDepthHandler`
2025-12-05 18:12:32 -03:00
Gustavo Henrique Santos Souza de Miranda 92b4b21e60 Remove duplicate `TransportProtocol.Response.newBuilder()` call in `CreateBitDepthHandler`. 2025-12-05 17:02:02 -03:00
13 changed files with 576 additions and 2 deletions

View File

@ -0,0 +1,39 @@
package com.mediamanager.mapper;
import com.mediamanager.model.BitRate;
import com.mediamanager.protocol.messages.BitRateMessages;
public class BitRateMapper {
public static BitRateMessages.BitRate toProtobuf(BitRate entity) {
if (entity == null) {
return null;
}
String value = entity.getValue();
if (value == null) {
throw new IllegalArgumentException("Bit rate value cannot be null");
}
BitRateMessages.BitRate.Builder builder = BitRateMessages.BitRate.newBuilder()
.setValue(value);
Integer id = entity.getId();
if (id != null && id > 0) {
builder.setId(id);
}
return builder.build();
}
public static BitRate toEntity(BitRateMessages.BitRate protobuf) {
if (protobuf == null) {
return null;
}
BitRate entity = new BitRate();
if (protobuf.getId() > 0) {
entity.setId(protobuf.getId());
}
entity.setValue(protobuf.getValue());
return entity;
}
}

View File

@ -0,0 +1,31 @@
package com.mediamanager.model;
import jakarta.persistence.*;
@Entity
@Table(name = "bit_rate")
public class BitRate {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(nullable = false)
private String value;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -0,0 +1,101 @@
package com.mediamanager.repository;
import com.mediamanager.model.BitRate;
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 BitRateRepository {
private static final Logger logger = LogManager.getLogger(BitRateRepository.class);
private final EntityManagerFactory entityManagerFactory;
public BitRateRepository(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
public BitRate save(BitRate bitRate) {
logger.debug("Saving BitRate: {}", bitRate.getValue());
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
try {
em.persist(bitRate);
em.getTransaction().commit();
logger.debug("BitRate saved with ID: {}", bitRate.getId());
return bitRate;
} catch (Exception e) {
em.getTransaction().rollback();
logger.error("Error saving BitRate", e);
throw e;
} finally {
if (em.isOpen()) em.close();
}
}
public List<BitRate> findAll(){
logger.debug("Finding all BitRates");
EntityManager em = entityManagerFactory.createEntityManager();
try{
return em.createQuery("SELECT b FROM BitRate b ORDER BY b.value", BitRate.class).getResultList();
}finally {
if (em.isOpen()) em.close();
}
}
public Optional<BitRate> findById(Integer id){
logger.debug("Finding BitRate by ID: {}", id);
EntityManager em = entityManagerFactory.createEntityManager();
try{
BitRate bitRate = em.find(BitRate.class, id);
return Optional.ofNullable(bitRate);
} finally {
if (em.isOpen()) em.close();
}
}
public BitRate update(BitRate bitRate){
logger.debug("Updating BitRate ID: {}", bitRate.getId());
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
try{
BitRate updated = em.merge(bitRate);
em.getTransaction().commit();
logger.debug("BitRate updated with ID: {}", bitRate.getId());
return updated;
} catch (Exception e) {
em.getTransaction().rollback();
logger.error("Error updating BitRate", e);
throw e;
} finally {
if (em.isOpen()) em.close();
}
}
public boolean deleteById(Integer id){
logger.debug("Deleting BitRate by ID: {}", id);
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
try{
BitRate bitRate = em.find(BitRate.class, id);
if (bitRate == null) {
em.getTransaction().rollback();
return false;
}
em.remove(bitRate);
em.getTransaction().commit();
logger.debug("BitRate deleted successfully");
return true;
} catch (Exception e) {
em.getTransaction().rollback();
logger.error("Error deleting BitRate", e);
throw e;
} finally {
if (em.isOpen()) em.close();
}
}
}

View File

@ -0,0 +1,65 @@
package com.mediamanager.service.bitrate;
import com.mediamanager.model.BitRate;
import com.mediamanager.repository.BitRateRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Optional;
public class BitRateService {
private static final Logger logger = LogManager.getLogger(BitRateService.class);
private final BitRateRepository bitRateRepository;
public BitRateService(BitRateRepository bitRateRepository) {
this.bitRateRepository = bitRateRepository;
}
public BitRate createBitRate(String value){
logger.info("Creating bit-rate: {}",value);
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException("Bit-rate value cannot be empty");
}
BitRate bitRate = new BitRate();
bitRate.setValue(value.trim());
return bitRateRepository.save(bitRate);
}
public List<BitRate> getAllBitRates(){
logger.info("Getting all bit-rates");
return bitRateRepository.findAll();
}
public Optional<BitRate> getBitRateById(Integer id){
logger.info("Getting bit-rate by ID: {}", id);
return bitRateRepository.findById(id);
}
public Optional<BitRate> updateBitRate(Integer id, String value){
logger.info("Updating bit-rate ID {}: {}", id, value);
if (value == null || value.trim().isEmpty()) {
throw new IllegalArgumentException("Bit-rate value cannot be empty");
}
Optional<BitRate> existingBitRate = bitRateRepository.findById(id);
if(existingBitRate.isEmpty()) {
logger.warn("Bit-rate not found with ID: {}", id);
return Optional.empty();
}
BitRate bitRate = existingBitRate.get();
bitRate.setValue(value.trim());
BitRate updatedBitRate = bitRateRepository.update(bitRate);
return Optional.of(updatedBitRate);
}
public boolean deleteBitRate(Integer id){
logger.info("Deleting bit-rate ID: {}", id);
return bitRateRepository.deleteById(id);
}
}

View File

@ -4,6 +4,7 @@ import com.google.protobuf.ByteString;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.repository.*;
import com.mediamanager.service.bitdepth.BitDepthService;
import com.mediamanager.service.bitrate.BitRateService;
import com.mediamanager.service.composer.ComposerService;
import com.mediamanager.repository.GenreRepository;
import com.mediamanager.service.artist.ArtistService;
@ -65,6 +66,10 @@ public class DelegateActionManager {
BitDepthService bitDepthService = new BitDepthService(bitDepthRepository);
serviceLocator.register(BitDepthService.class, bitDepthService);
BitRateRepository bitRateRepository = new BitRateRepository(entityManagerFactory);
BitRateService bitRateService = new BitRateService(bitRateRepository);
serviceLocator.register(BitRateService.class, bitRateService);
serviceLocator.logRegisteredServices();
logger.info("Services initialized successfully");

View File

@ -42,7 +42,6 @@ public class CreateBitDepthHandler implements ActionHandler {
} catch (Exception e) {
logger.error("Error creating bit-depth", e);
return TransportProtocol.Response.newBuilder()
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));

View File

@ -0,0 +1,50 @@
package com.mediamanager.service.delegate.handler.bitrate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mediamanager.mapper.BitRateMapper;
import com.mediamanager.model.BitRate;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.protocol.messages.BitRateMessages;
import com.mediamanager.service.bitrate.BitRateService;
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("bitrate.create")
public class CreateBitRateHandler implements ActionHandler {
private static final Logger logger = LogManager.getLogger(CreateBitRateHandler.class);
private final BitRateService bitRateService;
public CreateBitRateHandler(BitRateService bitRateService) {
this.bitRateService = bitRateService;
}
@Override
public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
try{
BitRateMessages.CreateBitRateRequest createRequest =
BitRateMessages.CreateBitRateRequest.parseFrom(requestPayload);
BitRate bitRate = bitRateService.createBitRate(createRequest.getValue());
BitRateMessages.BitRate BitRateProto = BitRateMapper.toProtobuf(bitRate);
BitRateMessages.CreateBitRateResponse createBitRateResponse = BitRateMessages.CreateBitRateResponse.newBuilder()
.setBitrate(BitRateProto)
.build();
return TransportProtocol.Response.newBuilder()
.setPayload(createBitRateResponse.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 bit-rate", e);
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
}
}
}

View File

@ -0,0 +1,62 @@
package com.mediamanager.service.delegate.handler.bitrate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.protocol.messages.BitRateMessages;
import com.mediamanager.service.bitrate.BitRateService;
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("bitrate.delete")
public class DeleteBitRateHandler implements ActionHandler {
private static final Logger logger = LogManager.getLogger(DeleteBitRateHandler.class);
private final BitRateService bitRateService;
public DeleteBitRateHandler(BitRateService bitRateService) {
this.bitRateService = bitRateService;
}
@Override
public TransportProtocol.Response.Builder handle(ByteString requestPayload)
throws InvalidProtocolBufferException {
try {
BitRateMessages.DeleteBitRateRequest deleteRequest =
BitRateMessages.DeleteBitRateRequest.parseFrom(requestPayload);
int id = deleteRequest.getId();
boolean success = bitRateService.deleteBitRate(id);
BitRateMessages.DeleteBitRateResponse deleteResponse;
if (success) {
deleteResponse = BitRateMessages.DeleteBitRateResponse.newBuilder()
.setSuccess(true)
.setMessage("Bit-Rate deleted successfully")
.build();
return TransportProtocol.Response.newBuilder()
.setPayload(deleteResponse.toByteString());
} else {
deleteResponse = BitRateMessages.DeleteBitRateResponse.newBuilder()
.setSuccess(false)
.setMessage("Bit-Rate not found")
.build();
return TransportProtocol.Response.newBuilder()
.setStatusCode(404)
.setPayload(deleteResponse.toByteString());
}
} catch (Exception e) {
logger.error("Error deleting bit-rate", e);
BitRateMessages.DeleteBitRateResponse deleteResponse =
BitRateMessages.DeleteBitRateResponse.newBuilder()
.setSuccess(false)
.setMessage("Error: " + e.getMessage())
.build();
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(deleteResponse.toByteString());
}
}
}

View File

@ -0,0 +1,56 @@
package com.mediamanager.service.delegate.handler.bitrate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mediamanager.mapper.BitRateMapper;
import com.mediamanager.model.BitRate;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.protocol.messages.BitRateMessages;
import com.mediamanager.service.bitrate.BitRateService;
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(value = "bitrate.getById")
public class GetBitRateByIdHandler implements ActionHandler {
private static final Logger logger = LogManager.getLogger(GetBitRateByIdHandler.class);
private final BitRateService bitRateService;
public GetBitRateByIdHandler(BitRateService bitRateService) {
this.bitRateService = bitRateService;
}
@Override
public TransportProtocol.Response.Builder handle(ByteString requestPayload)
throws InvalidProtocolBufferException{
try{
BitRateMessages.GetBitRateByIdRequest getByIdRequest =
BitRateMessages.GetBitRateByIdRequest.parseFrom(requestPayload);
int id = getByIdRequest.getId();
Optional<BitRate> bitRateOpt = bitRateService.getBitRateById(id);
if (bitRateOpt.isEmpty()){
logger.warn("BitRate not found with ID: {}", id);
return TransportProtocol.Response.newBuilder()
.setStatusCode(404)
.setPayload(ByteString.copyFromUtf8("BitRate not found"));
}
BitRateMessages.BitRate bitRateProto = BitRateMapper.toProtobuf(bitRateOpt.get());
BitRateMessages.GetBitRateByIdResponse getByIdResponse = BitRateMessages.GetBitRateByIdResponse.newBuilder()
.setBitrate(bitRateProto)
.build();
return TransportProtocol.Response.newBuilder()
.setPayload(getByIdResponse.toByteString());
} catch (Exception e) {
logger.error("Error getting bit-rate by ID", e);
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(ByteString.copyFromUtf8("Error: "+ e.getMessage()));
}
}
}

View File

@ -0,0 +1,48 @@
package com.mediamanager.service.delegate.handler.bitrate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mediamanager.mapper.BitRateMapper;
import com.mediamanager.model.BitRate;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.protocol.messages.BitRateMessages;
import com.mediamanager.service.bitrate.BitRateService;
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("bitrate.getAll")
public class GetBitRateHandler implements ActionHandler {
private static final Logger logger = LogManager.getLogger(GetBitRateHandler.class);
private final BitRateService bitRateService;
public GetBitRateHandler(BitRateService bitRateService){this.bitRateService = bitRateService;}
@Override
public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
try{
List<BitRate> bitRates = bitRateService.getAllBitRates();
BitRateMessages.GetBitRatesResponse.Builder responseBuilder = BitRateMessages.GetBitRatesResponse.newBuilder();
for (BitRate bitRate : bitRates) {
BitRateMessages.BitRate bitRateProto = BitRateMapper.toProtobuf(bitRate);
responseBuilder.addBitrates(bitRateProto);
}
BitRateMessages.GetBitRatesResponse getBitRatesResponse = responseBuilder.build();
return TransportProtocol.Response.newBuilder()
.setPayload(getBitRatesResponse.toByteString());
}catch (Exception e){
logger.error("Error getting bit-rates", e);
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
}
}
}

View File

@ -0,0 +1,65 @@
package com.mediamanager.service.delegate.handler.bitrate;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import com.mediamanager.mapper.BitRateMapper;
import com.mediamanager.model.BitRate;
import com.mediamanager.protocol.TransportProtocol;
import com.mediamanager.protocol.messages.BitRateMessages;
import com.mediamanager.service.bitrate.BitRateService;
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("bitrate.update")
public class UpdateBitRateHandler implements ActionHandler {
private static final Logger logger = LogManager.getLogger(UpdateBitRateHandler.class);
private final BitRateService bitRateService;
public UpdateBitRateHandler(BitRateService bitRateService) {
this.bitRateService = bitRateService;
}
@Override
public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
try{
BitRateMessages.UpdateBitRateRequest updateRequest =
BitRateMessages.UpdateBitRateRequest.parseFrom(requestPayload);
int id = updateRequest.getId();
String newValue = updateRequest.getValue();
Optional<BitRate> bitRateOpt = bitRateService.updateBitRate(id, newValue);
if(bitRateOpt.isEmpty()){
logger.warn("BitRate not found with ID: {}", id);
return TransportProtocol.Response.newBuilder()
.setStatusCode(404)
.setPayload(ByteString.copyFromUtf8("BitRate not found"));
}
BitRateMessages.BitRate bitRateProto = BitRateMapper.toProtobuf(bitRateOpt.get());
BitRateMessages.UpdateBitRateResponse updateResponse = BitRateMessages.UpdateBitRateResponse.newBuilder()
.setBitrate(bitRateProto)
.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 bit-rate", e);
return TransportProtocol.Response.newBuilder()
.setStatusCode(500)
.setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
}
}
}

View File

@ -40,7 +40,7 @@ message UpdateArtistRequest {
}
message UpdateArtistResponse {
Artist Artist = 1;
Artist artist = 1;
}
message DeleteArtistRequest {

View File

@ -0,0 +1,53 @@
syntax = "proto3";
option java_package = "com.mediamanager.protocol.messages";
option java_outer_classname = "BitRateMessages";
package mediamanager.messages;
message BitRate{
int32 id =1;
string value = 2;
}
message CreateBitRateRequest{
string value = 1;
}
message CreateBitRateResponse{
BitRate bitrate = 1;
}
message GetBitRatesRequest{
}
message GetBitRatesResponse{
repeated BitRate bitrates = 1;
}
message GetBitRateByIdRequest{
int32 id = 1;
}
message GetBitRateByIdResponse{
BitRate bitrate = 1;
}
message UpdateBitRateRequest{
int32 id = 1;
string value = 2;
}
message UpdateBitRateResponse{
BitRate bitrate = 1;
}
message DeleteBitRateRequest{
int32 id =1;
}
message DeleteBitRateResponse{
bool success = 1;
string message = 2;
}