diff --git a/.gitignore b/.gitignore
index 5074d96..30116b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,8 +39,16 @@ build/
.DS_Store
### Application Specific ###
-application-local.properties
+config-local.properties
*.db
pipes/
*.log
/.idea/
+
+ Configuration files with sensitive credentials
+# These files contain database passwords and API keys and should never be committed
+src/main/resources/config.properties
+src/main/resources/application.properties
+
+# Allow example configuration files to be committed
+!src/main/resources/*.properties.example
\ No newline at end of file
diff --git a/README.md b/README.md
index baf75eb..56207a1 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ MediaManager-Core/
│ │ ├── util/ # Utility classes
│ │ └── MediaManagerApplication.java
│ └── resources/
-│ ├── application.properties # App configuration
+│ ├── config.properties # App configuration
│ ├── log4j2.xml # Logging configuration
│ └── META-INF/
│ └── persistence.xml # JPA configuration
@@ -55,7 +55,7 @@ GRANT ALL PRIVILEGES ON DATABASE mediamanager TO mediamanager;
### 2. Configuration
-Edit `src/main/resources/application.properties` and update the database credentials:
+Edit `src/main/resources/config.properties` and update the database credentials:
```properties
db.url=jdbc:postgresql://localhost:5432/mediamanager
@@ -90,7 +90,7 @@ The application creates named pipes for inter-process communication. Default con
- Pipe name: `mediamanager-pipe`
- Buffer size: 8192 bytes
-You can modify these settings in `application.properties`.
+You can modify these settings in `config.properties`.
## Logging
@@ -116,8 +116,8 @@ mvn test
## Dependencies
-- PostgreSQL Driver: 42.7.3
-- Hibernate ORM: 6.4.4.Final
+- PostgreSQL Driver: 42.7.5
+- Hibernate ORM: 7.1.7.Final
- HikariCP: 5.1.0
- Log4j 2: 2.23.1
- Jackson: 2.16.1
diff --git a/pom.xml b/pom.xml
index 9a87f4d..8846994 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
17
UTF-8
7.1.7.Final
- 42.7.5
+ 42.7.7
5.1.0
2.23.1
5.10.2
@@ -35,6 +35,12 @@
${hibernate.version}
+
+ org.hibernate.orm
+ hibernate-community-dialects
+ ${hibernate.version}
+
+
com.zaxxer
@@ -55,7 +61,7 @@
org.apache.logging.log4j
- log4j-slf4j2-impl
+ log4j-slf4j-impl
${log4j.version}
@@ -78,9 +84,32 @@
${junit.version}
test
+
+ com.google.protobuf
+ protobuf-java
+ 4.32.0
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.44.1.0
+
+
+ org.reflections
+ reflections
+ 0.10.2
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ 1.7.1
+
+
+
org.apache.maven.plugins
@@ -91,11 +120,75 @@
17
+
org.apache.maven.plugins
maven-surefire-plugin
3.2.5
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ 0.6.1
+
+ /usr/bin/protoc
+ ${project.basedir}/src/main/proto
+ ${project.build.directory}/generated-sources/protobuf/java
+ false
+
+
+
+
+ compile
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.5.0
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ ${project.build.directory}/generated-sources/protobuf/java
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.5.1
+
+
+ package
+
+ shade
+
+
+
+
+ com.mediamanager.MediaManagerApplication
+
+
+
+
+
+
diff --git a/src/main/java/com/mediamanager/MediaManagerApplication.java b/src/main/java/com/mediamanager/MediaManagerApplication.java
index d3030da..22834fb 100644
--- a/src/main/java/com/mediamanager/MediaManagerApplication.java
+++ b/src/main/java/com/mediamanager/MediaManagerApplication.java
@@ -1,5 +1,8 @@
package com.mediamanager;
+import com.mediamanager.service.database.DatabaseManager;
+import com.mediamanager.service.delegate.DelegateActionManager;
+import com.mediamanager.service.ipc.IPCManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -7,9 +10,25 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
+import com.mediamanager.service.database.SqliteDatabaseManager;
+
public class MediaManagerApplication {
private static final Logger logger = LogManager.getLogger(MediaManagerApplication.class);
private static Properties config;
+ private static DatabaseManager databaseManager;
+ private static DelegateActionManager actionManager;
+ private static IPCManager ipcManager;
+
+ public enum ApplicationMode {
+ LOCAL("local"),
+ SERVER("server");
+
+ private final String value;
+
+ ApplicationMode(String value) {
+ this.value = value;
+ }
+ }
public static void main(String[] args) {
logger.info("Starting MediaManager Core Application...");
@@ -17,19 +36,85 @@ public class MediaManagerApplication {
try {
// Load configuration
loadConfiguration();
+ String runTypeString = config.getProperty("runtype","local");
+ ApplicationMode mode = null;
+
+ for (ApplicationMode am : ApplicationMode.values()) {
+ if (am.value.equalsIgnoreCase(runTypeString)) {
+ mode = am;
+ break;
+ }
+ }
+ if (mode == null) {
+ logger.error("Invalid run type: {}", runTypeString);
+ throw new Exception("Invalid run type: " + runTypeString);
+ }
+ logger.info("Run type: {}", mode);
+ switch (mode) {
+ case LOCAL:
+ logger.info("Starting local database...");
+ databaseManager = new SqliteDatabaseManager(config);
+ break;
+ case SERVER:
+ throw new Exception("Server mode not yet implemented");
+ default:
+ }
+ databaseManager.init();
+ actionManager = new DelegateActionManager(databaseManager.getEntityManagerFactory());
+ actionManager.start();
+ ipcManager = new IPCManager(config,actionManager);
+ ipcManager.init();
- // TODO: Initialize database connection
- // TODO: Initialize IPC server with named pipes
// TODO: Start application services
logger.info("MediaManager Core started successfully");
- logger.info("IPC Pipe: {}", config.getProperty("ipc.pipe.path") + "/" + config.getProperty("ipc.pipe.name"));
+ logger.info("IPC Socket: {}", ipcManager.getSocketPath().toAbsolutePath().toString());
// Keep application running
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+
logger.info("Shutting down MediaManager Core...");
- // TODO: Cleanup resources
+
+
+ if (databaseManager != null) {
+ databaseManager.close();
+ }
+
+ if (ipcManager != null) {
+ try {
+ ipcManager.close();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ if (actionManager != null) {
+ actionManager.stop();
+ }
+
+ logger.info("MediaManager Core shutdown successfully");
+ logger.info("Goodbye!");
+
+
+ // Give Log4j2 time to write all pending messages before shutting down
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ // Now shutdown Log4j2
+ org.apache.logging.log4j.LogManager.shutdown();
}));
+ logger.info("Application is running");
+ logger.info("Press Ctrl+C to exit");
+ Thread.currentThread().join();
+
+ } catch (InterruptedException e) {
+
+ logger.info("Application interrupted, initiating shutdown...");
+
+ Thread.currentThread().interrupt();
} catch (Exception e) {
logger.error("Failed to start MediaManager Core", e);
@@ -39,10 +124,9 @@ public class MediaManagerApplication {
private static void loadConfiguration() throws IOException {
config = new Properties();
- try (InputStream input = MediaManagerApplication.class.getClassLoader()
- .getResourceAsStream("application.properties")) {
+ try (InputStream input = MediaManagerApplication.class.getClassLoader().getResourceAsStream("config.properties")) {
if (input == null) {
- throw new IOException("Unable to find application.properties");
+ throw new IOException("Unable to find config.properties");
}
config.load(input);
logger.info("Configuration loaded successfully");
@@ -52,4 +136,4 @@ public class MediaManagerApplication {
public static Properties getConfig() {
return config;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/mapper/ArtistMapper.java b/src/main/java/com/mediamanager/mapper/ArtistMapper.java
new file mode 100644
index 0000000..29f2ce9
--- /dev/null
+++ b/src/main/java/com/mediamanager/mapper/ArtistMapper.java
@@ -0,0 +1,41 @@
+package com.mediamanager.mapper;
+
+import com.mediamanager.model.Artist;
+import com.mediamanager.protocol.messages.ArtistMessages;
+
+
+public class ArtistMapper {
+ public static ArtistMessages.Artist toProtobuf(Artist entity){
+ if (entity == null) {
+ return null;
+ }
+
+ String name = entity.getName();
+ if (name == null) {
+ throw new IllegalArgumentException("Artist name cannot be null");
+ }
+
+ ArtistMessages.Artist.Builder builder = ArtistMessages.Artist.newBuilder()
+ .setName(name);
+
+ // Only set ID when it's present and valid (> 0). Avoids NPE for null IDs.
+ Integer id = entity.getId();
+ if (id != null && id > 0) {
+ builder.setId(id);
+ }
+
+ return builder.build();
+ }
+ public static Artist toEntity(ArtistMessages.Artist protobuf) {
+ if (protobuf == null) {
+ return null;
+ }
+ Artist entity = new Artist();
+
+ if (protobuf.getId() > 0) {
+ entity.setId(protobuf.getId());
+ }
+ entity.setName(protobuf.getName());
+ return entity;
+ }
+}
diff --git a/src/main/java/com/mediamanager/mapper/BitDepthMapper.java b/src/main/java/com/mediamanager/mapper/BitDepthMapper.java
new file mode 100644
index 0000000..873629c
--- /dev/null
+++ b/src/main/java/com/mediamanager/mapper/BitDepthMapper.java
@@ -0,0 +1,39 @@
+package com.mediamanager.mapper;
+
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+
+public class BitDepthMapper {
+ public static BitDepthMessages.BitDepth toProtobuf(BitDepth entity) {
+ if (entity == null){
+ return null;
+ }
+
+ String value = entity.getValue();
+ if (value == null) {
+ throw new IllegalArgumentException("Bit depth value cannot be null");
+ }
+ BitDepthMessages.BitDepth.Builder builder = BitDepthMessages.BitDepth.newBuilder()
+ .setValue(value);
+
+ Integer id = entity.getId();
+ if (id != null && id > 0) {
+ builder.setId(id);
+ }
+
+ return builder.build();
+ }
+
+ public static BitDepth toEntity(BitDepthMessages.BitDepth protobuf) {
+ if (protobuf == null) {
+ return null;
+ }
+ BitDepth entity = new BitDepth();
+
+ if (protobuf.getId() > 0) {
+ entity.setId(protobuf.getId());
+ }
+ entity.setValue(protobuf.getValue());
+ return entity;
+ }
+}
diff --git a/src/main/java/com/mediamanager/mapper/BitRateMapper.java b/src/main/java/com/mediamanager/mapper/BitRateMapper.java
new file mode 100644
index 0000000..b6e5c5c
--- /dev/null
+++ b/src/main/java/com/mediamanager/mapper/BitRateMapper.java
@@ -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;
+ }
+}
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/mapper/GenreMapper.java b/src/main/java/com/mediamanager/mapper/GenreMapper.java
new file mode 100644
index 0000000..331e67c
--- /dev/null
+++ b/src/main/java/com/mediamanager/mapper/GenreMapper.java
@@ -0,0 +1,40 @@
+package com.mediamanager.mapper;
+
+import com.mediamanager.model.Genre;
+import com.mediamanager.protocol.messages.GenreMessages;
+
+public class GenreMapper {
+ public static GenreMessages.Genre toProtobuf(Genre entity) {
+ if (entity == null) {
+ return null;
+ }
+
+ GenreMessages.Genre.Builder builder = GenreMessages.Genre.newBuilder()
+ .setName(entity.getName());
+
+ // Only set ID when it's present and valid (> 0). Avoids NPE for null IDs.
+ Integer id = entity.getId();
+ if (id != null && id > 0) {
+ builder.setId(id);
+ }
+
+ return builder.build();
+ }
+ public static Genre toEntity(GenreMessages.Genre protobuf) {
+ if (protobuf == null) {
+ return null;
+ }
+
+ Genre entity = new Genre();
+
+ // Só seta ID se for > 0 (protobuf default é 0)
+ if (protobuf.getId() > 0) {
+ entity.setId(protobuf.getId());
+ }
+
+ entity.setName(protobuf.getName());
+
+ return entity;
+ }
+}
+
diff --git a/src/main/java/com/mediamanager/model/Artist.java b/src/main/java/com/mediamanager/model/Artist.java
new file mode 100644
index 0000000..22fe490
--- /dev/null
+++ b/src/main/java/com/mediamanager/model/Artist.java
@@ -0,0 +1,27 @@
+package com.mediamanager.model;
+
+import jakarta.persistence.*;
+
+@Entity
+@Table(name = "artist")
+public class Artist {
+ @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/model/BitDepth.java b/src/main/java/com/mediamanager/model/BitDepth.java
new file mode 100644
index 0000000..3b80217
--- /dev/null
+++ b/src/main/java/com/mediamanager/model/BitDepth.java
@@ -0,0 +1,32 @@
+package com.mediamanager.model;
+
+import jakarta.persistence.*;
+
+@Entity
+@Table(name = "bit_depth")
+public class BitDepth {
+
+ @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;
+ }
+}
+
diff --git a/src/main/java/com/mediamanager/model/BitRate.java b/src/main/java/com/mediamanager/model/BitRate.java
new file mode 100644
index 0000000..c3f6fa2
--- /dev/null
+++ b/src/main/java/com/mediamanager/model/BitRate.java
@@ -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;
+ }
+}
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/model/Genre.java b/src/main/java/com/mediamanager/model/Genre.java
new file mode 100644
index 0000000..b2a736b
--- /dev/null
+++ b/src/main/java/com/mediamanager/model/Genre.java
@@ -0,0 +1,30 @@
+package com.mediamanager.model;
+
+import jakarta.persistence.*;
+
+@Entity
+@Table(name = "genre")
+public class Genre {
+ @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/model/Media.java b/src/main/java/com/mediamanager/model/Media.java
deleted file mode 100644
index 99a455d..0000000
--- a/src/main/java/com/mediamanager/model/Media.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.mediamanager.model;
-
-import jakarta.persistence.*;
-import java.time.LocalDateTime;
-
-@Entity
-@Table(name = "media")
-public class Media {
-
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private Long id;
-
- @Column(nullable = false)
- private String title;
-
- @Column(nullable = false, unique = true)
- private String filePath;
-
- @Enumerated(EnumType.STRING)
- @Column(nullable = false)
- private MediaType type;
-
- @Column
- private Long fileSize;
-
- @Column
- private String mimeType;
-
- @Column(name = "created_at", nullable = false, updatable = false)
- private LocalDateTime createdAt;
-
- @Column(name = "updated_at")
- private LocalDateTime updatedAt;
-
- @PrePersist
- protected void onCreate() {
- createdAt = LocalDateTime.now();
- updatedAt = LocalDateTime.now();
- }
-
- @PreUpdate
- protected void onUpdate() {
- updatedAt = LocalDateTime.now();
- }
-
- // Constructors
- public Media() {}
-
- public Media(String title, String filePath, MediaType type) {
- this.title = title;
- this.filePath = filePath;
- this.type = type;
- }
-
- // Getters and Setters
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getFilePath() {
- return filePath;
- }
-
- public void setFilePath(String filePath) {
- this.filePath = filePath;
- }
-
- public MediaType getType() {
- return type;
- }
-
- public void setType(MediaType type) {
- this.type = type;
- }
-
- public Long getFileSize() {
- return fileSize;
- }
-
- public void setFileSize(Long fileSize) {
- this.fileSize = fileSize;
- }
-
- public String getMimeType() {
- return mimeType;
- }
-
- public void setMimeType(String mimeType) {
- this.mimeType = mimeType;
- }
-
- public LocalDateTime getCreatedAt() {
- return createdAt;
- }
-
- public void setCreatedAt(LocalDateTime createdAt) {
- this.createdAt = createdAt;
- }
-
- public LocalDateTime getUpdatedAt() {
- return updatedAt;
- }
-
- public void setUpdatedAt(LocalDateTime updatedAt) {
- this.updatedAt = updatedAt;
- }
-
- public enum MediaType {
- VIDEO,
- AUDIO,
- IMAGE,
- DOCUMENT,
- OTHER
- }
-}
diff --git a/src/main/java/com/mediamanager/repository/ArtistRepository.java b/src/main/java/com/mediamanager/repository/ArtistRepository.java
new file mode 100644
index 0000000..60d0b9d
--- /dev/null
+++ b/src/main/java/com/mediamanager/repository/ArtistRepository.java
@@ -0,0 +1,104 @@
+package com.mediamanager.repository;
+import com.mediamanager.model.Artist;
+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 ArtistRepository {
+ private static final Logger logger = LogManager.getLogger(ArtistRepository.class);
+
+ private final EntityManagerFactory entityManagerFactory;
+
+ public ArtistRepository(EntityManagerFactory entityManagerFactory) {
+ this.entityManagerFactory = entityManagerFactory;
+ }
+
+ public Artist save(Artist artist){
+ logger.debug("Saving Artist: {}", artist.getName());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ em.persist(artist);
+ em.getTransaction().commit();
+ logger.debug("Artist saved with ID: {}", artist.getId());
+ return artist;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error saving Artist", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public List findAll(){
+ logger.debug("Finding all Artists");
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try {
+ return em
+ .createQuery("SELECT a FROM Artist a ORDER BY a.name", Artist.class)
+ .getResultList();
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public Optional findById(Integer id){
+ logger.debug("Finding artist by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try {
+ Artist artist = em.find(Artist.class, id);
+ return Optional.ofNullable(artist);
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+
+ }
+
+ public Artist update(Artist artist){
+ logger.debug("Updating artist ID: {}", artist.getId());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ Artist updated = em.merge(artist);
+ em.getTransaction().commit();
+ logger.debug("Artist updated successfully");
+ return updated;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error updating artist", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public boolean deleteById(Integer id){
+ logger.debug("Deleting Artist by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ Artist artist = em.find(Artist.class, id);
+ if (artist == null) {
+ em.getTransaction().rollback();
+ return false;
+ }
+ em.remove(artist);
+ em.getTransaction().commit();
+ logger.debug("Artist deleted successfully");
+ return true;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error deleting artist", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+ }
+
+
diff --git a/src/main/java/com/mediamanager/repository/BitDepthRepository.java b/src/main/java/com/mediamanager/repository/BitDepthRepository.java
new file mode 100644
index 0000000..24b9dc9
--- /dev/null
+++ b/src/main/java/com/mediamanager/repository/BitDepthRepository.java
@@ -0,0 +1,100 @@
+package com.mediamanager.repository;
+
+import com.mediamanager.model.BitDepth;
+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 BitDepthRepository {
+ private static final Logger logger = LogManager.getLogger(BitDepthRepository.class);
+
+ private final EntityManagerFactory entityManagerFactory;
+
+ public BitDepthRepository(EntityManagerFactory entityManagerFactory) {
+ this.entityManagerFactory = entityManagerFactory;
+ }
+
+ public BitDepth save(BitDepth bitDepth) {
+ logger.debug("Saving BitDepth: {}", bitDepth.getValue());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ em.persist(bitDepth);
+ em.getTransaction().commit();
+ logger.debug("BitDepth saved with ID: {}", bitDepth.getId());
+ return bitDepth;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error saving BitDepth", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public List findAll(){
+ logger.debug("Finding all BitDepths");
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try{
+ return em.createQuery("SELECT b FROM BitDepth b ORDER BY b.value", BitDepth.class).getResultList();
+ }finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public Optional findById(Integer id){
+ logger.debug("Finding BitDepth by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try{
+ BitDepth bitDepth = em.find(BitDepth.class, id);
+ return Optional.ofNullable(bitDepth);
+ }finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public BitDepth update(BitDepth bitDepth){
+ logger.debug("Updating BitDepth ID: {}", bitDepth.getId());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try{
+ BitDepth updated = em.merge(bitDepth);
+ em.getTransaction().commit();
+ logger.debug("BitDepth updated successfully");
+ return updated;
+ }catch (Exception e){
+ em.getTransaction().rollback();
+ logger.error("Error updating BitDepth", e);
+ throw e;
+ }finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ public boolean deleteById(Integer id){
+ logger.debug("Deleting BitDepth by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try{
+ BitDepth bitDepth = em.find(BitDepth.class, id);
+ if (bitDepth == null) {
+ em.getTransaction().rollback();
+ return false;
+ }
+ em.remove(bitDepth);
+ em.getTransaction().commit();
+ logger.debug("BitDepth deleted successfully");
+ return true;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error deleting BitDepth", e);
+ throw e;
+ }finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/repository/BitRateRepository.java b/src/main/java/com/mediamanager/repository/BitRateRepository.java
new file mode 100644
index 0000000..42c5343
--- /dev/null
+++ b/src/main/java/com/mediamanager/repository/BitRateRepository.java
@@ -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 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 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();
+ }
+
+ }
+}
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/repository/GenreRepository.java b/src/main/java/com/mediamanager/repository/GenreRepository.java
new file mode 100644
index 0000000..73e9be9
--- /dev/null
+++ b/src/main/java/com/mediamanager/repository/GenreRepository.java
@@ -0,0 +1,121 @@
+package com.mediamanager.repository;
+
+import com.mediamanager.model.Genre;
+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;
+
+/**
+ * Repository para acesso a dados de Genre
+ * Encapsula todas as operações de banco de dados
+ */
+public class GenreRepository {
+ private static final Logger logger = LogManager.getLogger(GenreRepository.class);
+
+ private final EntityManagerFactory entityManagerFactory;
+
+ public GenreRepository(EntityManagerFactory entityManagerFactory) {
+ this.entityManagerFactory = entityManagerFactory;
+ }
+
+ /**
+ * Salva um novo genre
+ */
+ public Genre save(Genre genre) {
+ logger.debug("Saving genre: {}", genre.getName());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ em.persist(genre);
+ em.getTransaction().commit();
+ logger.debug("Genre saved with ID: {}", genre.getId());
+ return genre;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error saving genre", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ /**
+ * Busca todos os genres
+ */
+ public List findAll() {
+ logger.debug("Finding all genres");
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try {
+ return em
+ .createQuery("SELECT g FROM Genre g ORDER BY g.name", Genre.class)
+ .getResultList();
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ /**
+ * Busca genre por ID
+ */
+ public Optional findById(Integer id) {
+ logger.debug("Finding genre by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ try {
+ Genre genre = em.find(Genre.class, id);
+ return Optional.ofNullable(genre);
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ /**
+ * Atualiza um genre existente
+ */
+ public Genre update(Genre genre) {
+ logger.debug("Updating genre ID: {}", genre.getId());
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ Genre updated = em.merge(genre);
+ em.getTransaction().commit();
+ logger.debug("Genre updated successfully");
+ return updated;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error updating genre", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+
+ /**
+ * Deleta um genre por ID
+ */
+ public boolean deleteById(Integer id) {
+ logger.debug("Deleting genre by ID: {}", id);
+ EntityManager em = entityManagerFactory.createEntityManager();
+ em.getTransaction().begin();
+ try {
+ Genre genre = em.find(Genre.class, id);
+ if (genre == null) {
+ em.getTransaction().rollback();
+ return false;
+ }
+ em.remove(genre);
+ em.getTransaction().commit();
+ logger.debug("Genre deleted successfully");
+ return true;
+ } catch (Exception e) {
+ em.getTransaction().rollback();
+ logger.error("Error deleting genre", e);
+ throw e;
+ } finally {
+ if (em.isOpen()) em.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/artist/ArtistService.java b/src/main/java/com/mediamanager/service/artist/ArtistService.java
new file mode 100644
index 0000000..4686030
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/artist/ArtistService.java
@@ -0,0 +1,65 @@
+package com.mediamanager.service.artist;
+
+import com.mediamanager.model.Artist;
+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 ArtistService {
+ private static final Logger logger = LogManager.getLogger(ArtistService.class);
+ private final ArtistRepository artistRepository;
+
+ public ArtistService(ArtistRepository artistRepository) {
+ this.artistRepository = artistRepository;
+ }
+
+ public Artist createArtist(String name){
+ logger.info("Creating artist: {}", name);
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("Artist name cannot be empty");
+ }
+ Artist artist = new Artist();
+ artist.setName(name.trim());
+ return artistRepository.save(artist);
+ }
+
+ public List getAllArtists(){
+ logger.info("Getting all artists");
+ return artistRepository.findAll();
+ }
+
+ public Optional getArtistById(Integer id){
+ logger.info("Getting artist by ID: {}", id);
+ return artistRepository.findById(id);
+ }
+
+ public Optional updateArtist(Integer id, String name){
+ logger.info("Updating artist ID {}: {}", id, name);
+
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("Artist name cannot be empty");
+ }
+
+ Optional existingArtist = artistRepository.findById(id);
+
+ if(existingArtist.isEmpty()){
+ logger.warn("Artist not found with ID: {}", id);
+ return Optional.empty();
+ }
+ Artist artist = existingArtist.get();
+ artist.setName(name.trim());
+ Artist updatedArtist = artistRepository.update(artist);
+ return Optional.of(updatedArtist);
+ }
+
+ public boolean deleteArtist(Integer id){
+ logger.info("Deleting artist ID: {}", id);
+ return artistRepository.deleteById(id);
+ }
+
+
+
+}
diff --git a/src/main/java/com/mediamanager/service/bitdepth/BitDepthService.java b/src/main/java/com/mediamanager/service/bitdepth/BitDepthService.java
new file mode 100644
index 0000000..495e5d0
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/bitdepth/BitDepthService.java
@@ -0,0 +1,61 @@
+package com.mediamanager.service.bitdepth;
+
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.repository.BitDepthRepository;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+import java.util.Optional;
+
+public class BitDepthService {
+ private static final Logger logger = LogManager.getLogger(BitDepthService.class);
+ private final BitDepthRepository bitDepthRepository;
+
+ public BitDepthService(BitDepthRepository bitDepthRepository) {
+ this.bitDepthRepository = bitDepthRepository;
+ }
+ public BitDepth createBitDepth(String value){
+ logger.info("Creating bit-depth: {}", value);
+ if (value == null || value.trim().isEmpty()) {
+ throw new IllegalArgumentException("Bit-depth value cannot be empty");
+ }
+ BitDepth bitDepth = new BitDepth();
+ bitDepth.setValue(value.trim());
+ return bitDepthRepository.save(bitDepth);
+
+ }
+
+ public List getAllBitDepths(){
+ logger.info("Getting all bit-depths");
+ return bitDepthRepository.findAll();
+ }
+
+ public Optional getBitDepthById(Integer id){
+ logger.info("Getting bit-depth by ID: {}", id);
+ return bitDepthRepository.findById(id);
+ }
+
+ public Optional updateBitDepth(Integer id, String value){
+ logger.info("Updating bit-depth ID {}: {}", id, value);
+
+ if (value == null || value.trim().isEmpty()) {
+ throw new IllegalArgumentException("Bit-depth value cannot be empty");
+ }
+ Optional existingBitDepth = bitDepthRepository.findById(id);
+ if(existingBitDepth.isEmpty()){
+ logger.warn("Bit-depth not found with ID: {}", id);
+ return Optional.empty();
+ }
+ BitDepth bitDepth = existingBitDepth.get();
+ bitDepth.setValue(value.trim());
+ BitDepth updatedBitDepth = bitDepthRepository.update(bitDepth);
+ return Optional.of(updatedBitDepth);
+
+ }
+
+ public boolean deleteBitDepth(Integer id){
+ logger.info("Deleting bit-depth ID: {}", id);
+ return bitDepthRepository.deleteById(id);
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/bitrate/BitRateService.java b/src/main/java/com/mediamanager/service/bitrate/BitRateService.java
new file mode 100644
index 0000000..57e32db
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/bitrate/BitRateService.java
@@ -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 getAllBitRates(){
+ logger.info("Getting all bit-rates");
+ return bitRateRepository.findAll();
+ }
+
+ public Optional getBitRateById(Integer id){
+ logger.info("Getting bit-rate by ID: {}", id);
+ return bitRateRepository.findById(id);
+ }
+
+ public Optional 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 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);
+ }
+
+}
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/database/DatabaseManager.java b/src/main/java/com/mediamanager/service/database/DatabaseManager.java
new file mode 100644
index 0000000..13188a0
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/database/DatabaseManager.java
@@ -0,0 +1,142 @@
+package com.mediamanager.service.database;
+
+import jakarta.persistence.EntityManagerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.hibernate.cfg.Configuration;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import jakarta.persistence.Entity;
+import java.util.Set;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+
+public abstract class DatabaseManager {
+ protected final Properties configuration;
+ protected Connection connection;
+ protected String connectionUrl;
+ protected EntityManagerFactory entityManagerFactory;
+ protected static final Logger logger = LogManager.getLogger(DatabaseManager.class);
+
+ public DatabaseManager(Properties config) {
+ this.configuration = config;
+ logger.debug("DatabaseManager created with configuration:");
+ }
+
+ public abstract void init() throws Exception;
+
+ protected abstract Connection createConnection() throws Exception;
+
+ protected void performSanityChecks() throws SQLException {
+ logger.debug("Performing sanity checks...");
+ try (Statement stmt = connection.createStatement()) {
+ stmt.execute("SELECT 1");
+
+ }
+ String databaseProductName = connection.getMetaData().getDatabaseProductName();
+ String databaseProductVersion = connection.getMetaData().getDatabaseProductVersion();
+ logger.info("Connected to database: {} v{}", databaseProductName, databaseProductVersion);
+ }
+
+ public Connection getConnection() {
+ return connection;
+ }
+
+ public void close() {
+ if (entityManagerFactory != null && entityManagerFactory.isOpen()) {
+ try {
+ entityManagerFactory.close();
+ logger.info("EntityManagerFactory closed");
+ } catch (Exception e) {
+ logger.error("Error closing EntityManagerFactory: {}", e.getMessage());
+ }
+ }
+ if (connection != null) {
+ try {
+ logger.info("Closing database connection...");
+ connection.close();
+ logger.info("Database connection closed successfully");
+ } catch (SQLException e) {
+ logger.error("Error closing database connection: {}", e.getMessage());
+ }
+ } else {
+ logger.debug("No database connection to close");
+ }
+ }
+
+ protected boolean testConnection() {
+ try (Statement stmt = connection.createStatement()) {
+ stmt.execute("SELECT 1");
+ return true;
+ } catch (SQLException e) {
+ logger.error("Connection test failed", e);
+ return false;
+ }
+ }
+ protected void initializeHibernate() {
+ logger.info("Initializing Hibernate ORM...");
+
+ Configuration hibernateConfig = new Configuration();
+
+
+ String dialect = configuration.getProperty("hibernate.dialect");
+ String hbm2ddl = configuration.getProperty("hibernate.hbm2ddl.auto");
+ String driver = configuration.getProperty("database.driver");
+
+ if (dialect == null || dialect.isEmpty()) {
+ throw new IllegalStateException("hibernate.dialect property is required but not configured");
+ }
+ if (driver == null || driver.isEmpty()) {
+ throw new IllegalStateException("database.driver property is required but not configured");
+ }
+ if (connectionUrl == null || connectionUrl.isEmpty()) {
+ throw new IllegalStateException("connectionUrl must be set before initializing Hibernate");
+ }
+
+
+ hibernateConfig.setProperty("hibernate.connection.url", connectionUrl);
+ hibernateConfig.setProperty("hibernate.connection.driver_class", driver);
+ hibernateConfig.setProperty("hibernate.dialect", dialect);
+ hibernateConfig.setProperty("hibernate.hbm2ddl.auto", hbm2ddl);
+ hibernateConfig.setProperty("hibernate.show_sql",
+ configuration.getProperty("hibernate.show_sql", "false"));
+ hibernateConfig.setProperty("hibernate.format_sql",
+ configuration.getProperty("hibernate.format_sql", "true"));
+
+ logger.info("Scanning for entities in package: com.mediamanager.model");
+
+ Set> entityClasses;
+ try {
+ Reflections reflections = new Reflections("com.mediamanager.model", Scanners.TypesAnnotated);
+ entityClasses = reflections.getTypesAnnotatedWith(Entity.class);
+ } catch (Exception e) {
+ logger.error("Failed to scan for entities: {}", e.getMessage());
+ throw new RuntimeException("Entity scanning failed", e);
+ }
+
+ logger.info("Found {} entities", entityClasses.size());
+ if (entityClasses.isEmpty()) {
+ logger.warn("No @Entity classes found in package com.mediamanager.model - is this expected?");
+ }
+ for (Class> entityClass : entityClasses) {
+ logger.debug("Registering entity: {}", entityClass.getSimpleName());
+ hibernateConfig.addAnnotatedClass(entityClass);
+ }
+
+ try {
+ entityManagerFactory = hibernateConfig.buildSessionFactory().unwrap(EntityManagerFactory.class);
+ } catch (Exception e) {
+ logger.error("Failed to initialize Hibernate: {}", e.getMessage());
+ throw new RuntimeException("Hibernate initialization failed", e);
+ }
+
+ logger.info("Hibernate ORM initialized successfully");
+ }
+
+ public EntityManagerFactory getEntityManagerFactory() {
+ return entityManagerFactory;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/database/SqliteDatabaseManager.java b/src/main/java/com/mediamanager/service/database/SqliteDatabaseManager.java
new file mode 100644
index 0000000..dc98c91
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/database/SqliteDatabaseManager.java
@@ -0,0 +1,99 @@
+package com.mediamanager.service.database;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+public class SqliteDatabaseManager extends DatabaseManager {
+ private static final Logger logger = LogManager.getLogger(SqliteDatabaseManager.class);
+
+
+
+
+ public SqliteDatabaseManager(Properties config) {
+ super(config);
+ }
+
+ @Override
+ public void init() throws Exception {
+
+ logger.info("Initializing SQLite database...");
+ String dataDir = configuration.getProperty("database.dir",
+ System.getProperty("user.home") + "/.mediamanager/db");
+ String dbFilename = configuration.getProperty("database.filename", "mediamanager.db");
+ String driverClassName = configuration.getProperty("database.driver", "org.sqlite.JDBC");
+ try {
+ Class.forName(driverClassName);
+ }catch(ClassNotFoundException e) {
+ logger.error("Failed to load SQLite driver", e);
+ throw e;
+ }
+ Path dataPath = Paths.get(dataDir);
+ if (!Files.exists(dataPath)) {
+ Files.createDirectories(dataPath);
+ logger.debug("Created database directory: {}", dataDir);
+ }
+ Path dbFile = dataPath.resolve(dbFilename);
+ this.connectionUrl = "jdbc:sqlite:" + dbFile.toAbsolutePath().toString();
+ logger.info("Database file path: {}", dbFile);
+ logger.info("Connection URL: {}", this.connectionUrl);
+ initializeHibernate();
+ this.connection = createConnection();
+ configurePerformancePragmas();
+ performSanityChecks();
+ ensureSchemaExists();
+ logger.info("SQLite database initialized successfully");
+
+
+ }
+
+ @Override
+ protected Connection createConnection() throws Exception {
+ try {
+ // O driver org.xerial.sqlite-jdbc é carregado automaticamente aqui
+ Connection conn = DriverManager.getConnection(this.connectionUrl);
+ logger.debug("Got connection to SQLite file");
+ return conn;
+ } catch (SQLException e) {
+ logger.error("Failed to create SQLite connection", e);
+ throw new Exception("SQLite connection failed: " + e.getMessage(), e);
+ }
+ }
+
+
+ private void configurePerformancePragmas() throws SQLException {
+ try (Statement stmt = connection.createStatement()) {
+
+ stmt.execute("PRAGMA journal_mode=WAL;");
+
+
+ stmt.execute("PRAGMA foreign_keys=ON;");
+
+
+ stmt.execute("PRAGMA synchronous=NORMAL;");
+
+ stmt.execute("PRAGMA busy_timeout=5000;");
+
+ logger.debug("SQLite performance PRAGMAs applied (WAL, Synchronous, ForeignKeys).");
+ }
+ }
+
+ private void ensureSchemaExists() throws SQLException {
+
+ }
+
+ @Override
+ public void close() {
+
+ super.close();
+ logger.info("SQLite resources released.");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/ActionHandler.java b/src/main/java/com/mediamanager/service/delegate/ActionHandler.java
new file mode 100644
index 0000000..27228fc
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/ActionHandler.java
@@ -0,0 +1,11 @@
+package com.mediamanager.service.delegate;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TransportProtocol;
+
+@FunctionalInterface
+public interface ActionHandler {
+ TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException;
+}
+
diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java
new file mode 100644
index 0000000..67daf24
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java
@@ -0,0 +1,223 @@
+package com.mediamanager.service.delegate;
+
+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;
+import com.mediamanager.service.delegate.annotation.Action;
+
+import com.mediamanager.service.genre.GenreService;
+import jakarta.persistence.EntityManagerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.reflections.Reflections;
+import org.reflections.scanners.Scanners;
+import java.lang.reflect.Constructor;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class DelegateActionManager {
+ private static final Logger logger = LogManager.getLogger(DelegateActionManager.class);
+
+ private final Map handlerRegistry;
+ private final ServiceLocator serviceLocator;
+ private final EntityManagerFactory entityManagerFactory;
+
+
+ public DelegateActionManager(EntityManagerFactory entityManagerFactory) {
+ this.entityManagerFactory = entityManagerFactory;
+ this.serviceLocator = new ServiceLocator();
+
+ initializeServices();
+
+
+ logger.debug("DelegateActionManager created");
+ this.handlerRegistry = new HashMap<>();
+ autoRegisterHandlers();
+
+ }
+
+ private void initializeServices() {
+ logger.info("Initializing services...");
+
+
+ GenreRepository genreRepository = new GenreRepository(entityManagerFactory);
+ GenreService genreService = new GenreService(genreRepository);
+
+
+ serviceLocator.register(GenreService.class, genreService);
+
+ ArtistRepository artistRepository = new ArtistRepository(entityManagerFactory);
+ ArtistService artistService = new ArtistService(artistRepository);
+
+ serviceLocator.register(ArtistService.class, artistService);
+
+ ComposerRepository composerRepository = new ComposerRepository(entityManagerFactory);
+ ComposerService composerService = new ComposerService(composerRepository);
+ serviceLocator.register(ComposerService.class, composerService);
+
+ BitDepthRepository bitDepthRepository = new BitDepthRepository(entityManagerFactory);
+ 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");
+ }
+
+
+
+ public void start(){
+ logger.info("DelegateActionManager started");
+ }
+
+ public void stop(){
+ logger.info("DelegateActionManager stopped");
+ }
+
+ @SuppressWarnings("unchecked")
+ private ActionHandler instantiateHandler(Class> clazz) throws Exception {
+ if(!ActionHandler.class.isAssignableFrom(clazz)){
+ throw new IllegalArgumentException(
+ clazz.getName() + " is annotated with @Action but does not implement ActionHandler");
+
+ }
+ logger.debug("Attempting to instantiate handler: {}", clazz.getSimpleName());
+
+
+ Constructor>[] constructors = clazz.getDeclaredConstructors();
+
+
+ // Sort constructors by parameter count (descending) to prefer DI constructors
+ java.util.Arrays.sort(constructors, (c1, c2) ->
+ Integer.compare(c2.getParameterCount(), c1.getParameterCount()));
+
+ for (Constructor> constructor : constructors) {
+
+ Class>[] paramTypes = constructor.getParameterTypes();
+
+
+ Object[] params = new Object[paramTypes.length];
+ boolean allDependenciesResolved = true;
+
+ for (int i = 0; i < paramTypes.length; i++) {
+
+ Object service = serviceLocator.get(paramTypes[i]);
+
+ if (service == null) {
+
+ allDependenciesResolved = false;
+ logger.debug("Cannot resolve dependency {} for {}",
+ paramTypes[i].getSimpleName(),
+ clazz.getSimpleName());
+ break; // Para de tentar esse construtor
+ }
+
+
+ params[i] = service;
+ }
+
+
+ if (allDependenciesResolved) {
+ logger.debug("Using constructor with {} params for {}",
+ paramTypes.length, clazz.getSimpleName());
+ return (ActionHandler) constructor.newInstance(params);
+ }
+ }
+
+
+ throw new IllegalStateException(
+ String.format(
+ "Cannot instantiate handler %s. No suitable constructor found. " +
+ "Make sure all required services are registered in ServiceLocator.",
+ clazz.getName()
+ )
+ );
+ }
+
+ private void autoRegisterHandlers() {
+ logger.info("Starting auto-registration of handlers...");
+ Reflections reflections = new Reflections(
+ "com.mediamanager.service.delegate.handler",
+ Scanners.TypesAnnotated
+ );
+ Set> annotatedClasses = reflections.getTypesAnnotatedWith(Action.class);
+ logger.info("Found {} handler classes with @Action annotation", annotatedClasses.size());
+ int successCount = 0;
+ int failureCount = 0;
+ for (Class> handlerClass : annotatedClasses) {
+ try {
+
+ Action actionAnnotation = handlerClass.getAnnotation(Action.class);
+ String actionName = actionAnnotation.value();
+
+ logger.debug("Processing handler: {} for action '{}'",
+ handlerClass.getSimpleName(),
+ actionName);
+
+
+ ActionHandler handler = instantiateHandler(handlerClass);
+
+
+ handlerRegistry.put(actionName, handler);
+
+ logger.info("✓ Registered handler: '{}' -> {}",
+ actionName,
+ handlerClass.getSimpleName());
+ successCount++;
+
+ } catch (Exception e) {
+
+ logger.error("✗ Failed to register handler: {}",
+ handlerClass.getName(),
+ e);
+ failureCount++;
+ }
+ }
+
+
+ logger.info("Auto-registration complete: {} successful, {} failed, {} total",
+ successCount,
+ failureCount,
+ successCount + failureCount);
+
+ if (failureCount > 0) {
+ logger.warn("Some handlers failed to register. Check logs above for details.");
+ }
+ }
+
+ public TransportProtocol.Response ProcessedRequest(TransportProtocol.Request request){
+ String requestId = request.getRequestId();
+ logger.info("Processing request: {}", requestId);
+ String action = request.getHeadersMap().getOrDefault("action", "unknown");
+ ActionHandler handler = handlerRegistry.get(action);
+ TransportProtocol.Response.Builder responseBuilder;
+ if (handler == null) {
+ logger.warn("No handler found for action: {}", action);
+ responseBuilder = TransportProtocol.Response.newBuilder()
+ .setStatusCode(404) // 404 Not Found
+ .setPayload(ByteString.copyFromUtf8("Error: Action '" + action + "' not found."));
+ } else{
+ try {
+ logger.debug("Delegating action '{}' to handler...", action);
+ responseBuilder = handler.handle(request.getPayload());
+ }catch (Exception e) {
+ logger.error("Handler for action '{}' threw an exception:", action, e);
+ responseBuilder = TransportProtocol.Response.newBuilder()
+ .setStatusCode(500) // 500 Internal Server Error
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+ return responseBuilder.setRequestId(requestId).build();
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/ServiceLocator.java b/src/main/java/com/mediamanager/service/delegate/ServiceLocator.java
new file mode 100644
index 0000000..69886f4
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/ServiceLocator.java
@@ -0,0 +1,45 @@
+package com.mediamanager.service.delegate;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ServiceLocator {
+ private static final Logger logger = LogManager.getLogger(ServiceLocator.class);
+ private final Map, Object> services = new HashMap<>();
+
+ public void register(Class serviceClass, T serviceInstance) {
+ if (serviceInstance == null) {
+ throw new IllegalArgumentException("Service instance cannot be null");
+ }
+ services.put(serviceClass, serviceInstance);
+ logger.debug("Registered service: {} -> {}",
+ serviceClass.getSimpleName(),
+ serviceInstance.getClass().getSimpleName());
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get(Class serviceClass) {
+ return (T) services.get(serviceClass);
+ }
+
+ public boolean has(Class> serviceClass) {
+ return services.containsKey(serviceClass);
+ }
+ public int size() {
+ return services.size();
+ }
+ public void logRegisteredServices() {
+ logger.info("Registered services: {}", services.size());
+
+
+ services.forEach((clazz, instance) ->
+ logger.info(" - {} -> {}",
+ clazz.getSimpleName(),
+ instance.getClass().getSimpleName())
+ );
+ }
+}
+
diff --git a/src/main/java/com/mediamanager/service/delegate/annotation/Action.java b/src/main/java/com/mediamanager/service/delegate/annotation/Action.java
new file mode 100644
index 0000000..cac0db7
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/annotation/Action.java
@@ -0,0 +1,13 @@
+package com.mediamanager.service.delegate.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Action {
+
+ String value();
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java
new file mode 100644
index 0000000..9e9c658
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java
@@ -0,0 +1,34 @@
+package com.mediamanager.service.delegate.handler;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TestProtocol.CloseCommand;
+import com.mediamanager.protocol.TestProtocol.CloseResponse;
+import com.mediamanager.protocol.TransportProtocol;
+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("close")
+public class CloseHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(CloseHandler.class);
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+
+ CloseCommand.parseFrom(requestPayload); // Valida
+
+ logger.info("Close command received - connection will close");
+
+ CloseResponse response = CloseResponse.newBuilder()
+ .setMessage("Connection closing. Goodbye!")
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(ByteString.copyFrom(response.toByteArray()))
+ .setStatusCode(200)
+ .putHeaders("Connection", "close"); // ← Marca para fechar
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java
new file mode 100644
index 0000000..657c2e7
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java
@@ -0,0 +1,41 @@
+package com.mediamanager.service.delegate.handler;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TestProtocol.EchoCommand; // ← Import
+import com.mediamanager.protocol.TestProtocol.EchoResponse; // ← Import
+import com.mediamanager.protocol.TransportProtocol;
+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("echo")
+public class EchoHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(EchoHandler.class);
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException { // ← Pode lançar exceção
+
+ // 1. Parse Protobuf bytes → EchoCommand
+ EchoCommand command = EchoCommand.parseFrom(requestPayload);
+
+ logger.debug("Echo received: {}", command.getMessage());
+
+ // 2. Cria EchoResponse (Protobuf)
+ EchoResponse echoResponse = EchoResponse.newBuilder()
+ .setMessage(command.getMessage())
+ .setServerTimestamp(System.currentTimeMillis())
+ .build();
+
+ // 3. Serializa EchoResponse → bytes
+ ByteString responsePayload = ByteString.copyFrom(echoResponse.toByteArray());
+
+ // 4. Retorna Response
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(responsePayload)
+ .setStatusCode(200);
+
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java
new file mode 100644
index 0000000..d79270c
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java
@@ -0,0 +1,38 @@
+package com.mediamanager.service.delegate.handler;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TestProtocol.HeartbeatCommand;
+import com.mediamanager.protocol.TestProtocol.HeartbeatResponse;
+import com.mediamanager.protocol.TransportProtocol;
+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("heartbeat")
+public class HeartbeatHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(HeartbeatHandler.class);
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+
+ HeartbeatCommand command = HeartbeatCommand.parseFrom(requestPayload);
+
+ long serverTime = System.currentTimeMillis();
+
+ logger.debug("Heartbeat received. Client T1={}, Server T2={}",
+ command.getClientTimestamp(), serverTime);
+
+ HeartbeatResponse response = HeartbeatResponse.newBuilder()
+ .setClientTimestamp(command.getClientTimestamp()) // Echo T1
+ .setServerTimestamp(serverTime) // T2
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(ByteString.copyFrom(response.toByteArray()))
+ .setStatusCode(200);
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/artist/CreateArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/artist/CreateArtistHandler.java
new file mode 100644
index 0000000..268a4bd
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/artist/CreateArtistHandler.java
@@ -0,0 +1,50 @@
+package com.mediamanager.service.delegate.handler.artist;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.ArtistMapper;
+import com.mediamanager.model.Artist;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.service.artist.ArtistService;
+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("artist.create")
+public class CreateArtistHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(CreateArtistHandler.class);
+ private final ArtistService artistService;
+
+ public CreateArtistHandler(ArtistService artistService) {
+ this.artistService = artistService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ ArtistMessages.CreateArtistRequest createRequest =
+ ArtistMessages.CreateArtistRequest.parseFrom(requestPayload);
+ Artist artist = artistService.createArtist(createRequest.getName());
+ ArtistMessages.Artist artistProto = ArtistMapper.toProtobuf(artist);
+ ArtistMessages.CreateArtistResponse createArtistResponse = ArtistMessages.CreateArtistResponse.newBuilder()
+ .setArtist(artistProto)
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(createArtistResponse.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 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/artist/DeleteArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/artist/DeleteArtistHandler.java
new file mode 100644
index 0000000..a3d3c72
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/artist/DeleteArtistHandler.java
@@ -0,0 +1,62 @@
+package com.mediamanager.service.delegate.handler.artist;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.service.artist.ArtistService;
+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("artist.delete")
+public class DeleteArtistHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(DeleteArtistHandler.class);
+
+ private final ArtistService artistService;
+
+ public DeleteArtistHandler(ArtistService artistService) {
+ this.artistService = artistService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+
+ try {
+ ArtistMessages.DeleteArtistRequest deleteRequest =
+ ArtistMessages.DeleteArtistRequest.parseFrom(requestPayload);
+ int id = deleteRequest.getId();
+ boolean success = artistService.deleteArtist(id);
+ ArtistMessages.DeleteArtistResponse deleteResponse;
+ if (success) {
+ deleteResponse = ArtistMessages.DeleteArtistResponse.newBuilder()
+ .setSuccess(true)
+ .setMessage("Artist deleted successfully")
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(deleteResponse.toByteString());
+ } else {
+ deleteResponse = ArtistMessages.DeleteArtistResponse.newBuilder()
+ .setSuccess(false)
+ .setMessage("Artist not found")
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(deleteResponse.toByteString());
+ }
+ } catch (Exception e) {
+ logger.error("Error deleting artist", e);
+ ArtistMessages.DeleteArtistResponse deleteResponse =
+ ArtistMessages.DeleteArtistResponse.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/artist/GetArtistByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/artist/GetArtistByIdHandler.java
new file mode 100644
index 0000000..d98b48e
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/artist/GetArtistByIdHandler.java
@@ -0,0 +1,56 @@
+package com.mediamanager.service.delegate.handler.artist;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.ArtistMapper;
+import com.mediamanager.model.Artist;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.service.artist.ArtistService;
+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 = "artist.getById")
+public class GetArtistByIdHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetArtistByIdHandler.class);
+ private final ArtistService artistService;
+
+ public GetArtistByIdHandler(ArtistService artistService) {
+ this.artistService = artistService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException{
+
+ try{
+ ArtistMessages.GetArtistByIdRequest getByIdRequest =
+ ArtistMessages.GetArtistByIdRequest.parseFrom(requestPayload);
+ int id = getByIdRequest.getId();
+
+ Optional artistOpt = artistService.getArtistById(id);
+
+ if (artistOpt.isEmpty()){
+ logger.warn("Artist not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("Artist not found"));
+ }
+ ArtistMessages.Artist artistProto = ArtistMapper.toProtobuf(artistOpt.get());
+ ArtistMessages.GetArtistByIdResponse getByIdResponse = ArtistMessages.GetArtistByIdResponse.newBuilder()
+ .setArtist(artistProto)
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getByIdResponse.toByteString());
+ } catch (Exception e) {
+ logger.error("Error getting 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/artist/GetArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/artist/GetArtistHandler.java
new file mode 100644
index 0000000..bf91fff
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/artist/GetArtistHandler.java
@@ -0,0 +1,48 @@
+package com.mediamanager.service.delegate.handler.artist;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.ArtistMapper;
+import com.mediamanager.model.Artist;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.service.artist.ArtistService;
+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("artist.getAll")
+public class GetArtistHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetArtistHandler.class);
+
+ private final ArtistService artistService;
+
+ public GetArtistHandler(ArtistService artistService){this.artistService = artistService;}
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ List artists = artistService.getAllArtists();
+ ArtistMessages.GetArtistsResponse.Builder responseBuilder = ArtistMessages.GetArtistsResponse.newBuilder();
+
+ for (Artist artist : artists) {
+ ArtistMessages.Artist artistProto = ArtistMapper.toProtobuf(artist);
+ responseBuilder.addArtists(artistProto);
+ }
+ ArtistMessages.GetArtistsResponse getArtistsResponse = responseBuilder.build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getArtistsResponse.toByteString());
+
+ }catch (Exception e){
+ logger.error("Error getting artists", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/artist/UpdateArtistHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/artist/UpdateArtistHandler.java
new file mode 100644
index 0000000..69c3cd6
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/artist/UpdateArtistHandler.java
@@ -0,0 +1,65 @@
+package com.mediamanager.service.delegate.handler.artist;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.ArtistMapper;
+import com.mediamanager.model.Artist;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.service.artist.ArtistService;
+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("artist.update")
+public class UpdateArtistHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(UpdateArtistHandler.class);
+ private final ArtistService artistService;
+
+ public UpdateArtistHandler(ArtistService artistService) {
+ this.artistService = artistService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ ArtistMessages.UpdateArtistRequest updateRequest =
+ ArtistMessages.UpdateArtistRequest.parseFrom(requestPayload);
+
+ int id = updateRequest.getId();
+ String newName = updateRequest.getName();
+
+ Optional artistOpt = artistService.updateArtist(id, newName);
+
+ if(artistOpt.isEmpty()){
+ logger.warn("Artist not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("Artist not found"));
+ }
+
+ ArtistMessages.Artist artistProto = ArtistMapper.toProtobuf(artistOpt.get());
+
+ ArtistMessages.UpdateArtistResponse updateResponse = ArtistMessages.UpdateArtistResponse.newBuilder()
+ .setArtist(artistProto)
+ .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 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/bitdepth/CreateBitDepthHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/CreateBitDepthHandler.java
new file mode 100644
index 0000000..db9e034
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/CreateBitDepthHandler.java
@@ -0,0 +1,51 @@
+package com.mediamanager.service.delegate.handler.bitdepth;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.BitDepthMapper;
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.ArtistMessages;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+import com.mediamanager.service.bitdepth.BitDepthService;
+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("bitdepth.create")
+public class CreateBitDepthHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(CreateBitDepthHandler.class);
+ private final BitDepthService bitDepthService;
+
+ public CreateBitDepthHandler(BitDepthService bitDepthService) {
+ this.bitDepthService = bitDepthService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ BitDepthMessages.CreateBitDepthRequest createRequest =
+ BitDepthMessages.CreateBitDepthRequest.parseFrom(requestPayload);
+ BitDepth bitDepth = bitDepthService.createBitDepth(createRequest.getValue());
+ BitDepthMessages.BitDepth BitDepthProto = BitDepthMapper.toProtobuf(bitDepth);
+ BitDepthMessages.CreateBitDepthResponse createBitDepthResponse = BitDepthMessages.CreateBitDepthResponse.newBuilder()
+ .setBitdepth(BitDepthProto)
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(createBitDepthResponse.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-depth", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
+
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/DeleteBitDepthHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/DeleteBitDepthHandler.java
new file mode 100644
index 0000000..b71a9a1
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/DeleteBitDepthHandler.java
@@ -0,0 +1,62 @@
+package com.mediamanager.service.delegate.handler.bitdepth;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+import com.mediamanager.service.bitdepth.BitDepthService;
+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("bitdepth.delete")
+public class DeleteBitDepthHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(DeleteBitDepthHandler.class);
+
+ private final BitDepthService bitDepthService;
+
+ public DeleteBitDepthHandler(BitDepthService bitDepthService) {
+ this.bitDepthService = bitDepthService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+
+ try {
+ BitDepthMessages.DeleteBitDepthRequest deleteRequest =
+ BitDepthMessages.DeleteBitDepthRequest.parseFrom(requestPayload);
+ int id = deleteRequest.getId();
+ boolean success = bitDepthService.deleteBitDepth(id);
+ BitDepthMessages.DeleteBitDepthResponse deleteResponse;
+ if (success) {
+ deleteResponse = BitDepthMessages.DeleteBitDepthResponse.newBuilder()
+ .setSuccess(true)
+ .setMessage("Bit-Depth deleted successfully")
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(deleteResponse.toByteString());
+ } else {
+ deleteResponse = BitDepthMessages.DeleteBitDepthResponse.newBuilder()
+ .setSuccess(false)
+ .setMessage("Bit-Depth not found")
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(deleteResponse.toByteString());
+ }
+ } catch (Exception e) {
+ logger.error("Error deleting bit-depth", e);
+ BitDepthMessages.DeleteBitDepthResponse deleteResponse =
+ BitDepthMessages.DeleteBitDepthResponse.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/bitdepth/GetBitDepthByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/GetBitDepthByIdHandler.java
new file mode 100644
index 0000000..96e630d
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/GetBitDepthByIdHandler.java
@@ -0,0 +1,56 @@
+package com.mediamanager.service.delegate.handler.bitdepth;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.BitDepthMapper;
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+import com.mediamanager.service.bitdepth.BitDepthService;
+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 = "bitdepth.getById")
+public class GetBitDepthByIdHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetBitDepthByIdHandler.class);
+ private final BitDepthService bitDepthServicee;
+
+ public GetBitDepthByIdHandler(BitDepthService bitDepthServicee) {
+ this.bitDepthServicee = bitDepthServicee;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException{
+
+ try{
+ BitDepthMessages.GetBitDepthByIdRequest getByIdRequest =
+ BitDepthMessages.GetBitDepthByIdRequest.parseFrom(requestPayload);
+ int id = getByIdRequest.getId();
+
+ Optional bitDepthOpt = bitDepthServicee.getBitDepthById(id);
+
+ if (bitDepthOpt.isEmpty()){
+ logger.warn("BitDepth not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("BitDepth not found"));
+ }
+ BitDepthMessages.BitDepth bitDepthProto = BitDepthMapper.toProtobuf(bitDepthOpt.get());
+ BitDepthMessages.GetBitDepthByIdResponse getByIdResponse = BitDepthMessages.GetBitDepthByIdResponse.newBuilder()
+ .setBitdepth(bitDepthProto)
+ .build();
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getByIdResponse.toByteString());
+ } catch (Exception e) {
+ logger.error("Error getting bit-depth 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/bitdepth/GetBitDepthHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/GetBitDepthHandler.java
new file mode 100644
index 0000000..71cf92f
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/GetBitDepthHandler.java
@@ -0,0 +1,48 @@
+package com.mediamanager.service.delegate.handler.bitdepth;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.BitDepthMapper;
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+import com.mediamanager.service.bitdepth.BitDepthService;
+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("bitdepth.getAll")
+public class GetBitDepthHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetBitDepthHandler.class);
+
+ private final BitDepthService bitDepthService;
+
+ public GetBitDepthHandler(BitDepthService bitDepthService){this.bitDepthService = bitDepthService;}
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ List bitDepths = bitDepthService.getAllBitDepths();
+ BitDepthMessages.GetBitDepthsResponse.Builder responseBuilder = BitDepthMessages.GetBitDepthsResponse.newBuilder();
+
+ for (BitDepth bitDepth : bitDepths) {
+ BitDepthMessages.BitDepth bitDepthProto = BitDepthMapper.toProtobuf(bitDepth);
+ responseBuilder.addBitdepths(bitDepthProto);
+ }
+ BitDepthMessages.GetBitDepthsResponse getBitDepthsResponse = responseBuilder.build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getBitDepthsResponse.toByteString());
+
+ }catch (Exception e){
+ logger.error("Error getting bit-depths", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/UpdateBitDepthHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/UpdateBitDepthHandler.java
new file mode 100644
index 0000000..c786b12
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitdepth/UpdateBitDepthHandler.java
@@ -0,0 +1,65 @@
+package com.mediamanager.service.delegate.handler.bitdepth;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.BitDepthMapper;
+import com.mediamanager.model.BitDepth;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.BitDepthMessages;
+import com.mediamanager.service.bitdepth.BitDepthService;
+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("bitdepth.update")
+public class UpdateBitDepthHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(UpdateBitDepthHandler.class);
+ private final BitDepthService bitDepthService;
+
+ public UpdateBitDepthHandler(BitDepthService bitDepthService) {
+ this.bitDepthService = bitDepthService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload) throws InvalidProtocolBufferException {
+ try{
+ BitDepthMessages.UpdateBitDepthRequest updateRequest =
+ BitDepthMessages.UpdateBitDepthRequest.parseFrom(requestPayload);
+
+ int id = updateRequest.getId();
+ String newValue = updateRequest.getValue();
+
+ Optional bitDepthOpt = bitDepthService.updateBitDepth(id, newValue);
+
+ if(bitDepthOpt.isEmpty()){
+ logger.warn("BitDepth not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("BitDepth not found"));
+ }
+
+ BitDepthMessages.BitDepth bitDepthProto = BitDepthMapper.toProtobuf(bitDepthOpt.get());
+
+ BitDepthMessages.UpdateBitDepthResponse updateResponse = BitDepthMessages.UpdateBitDepthResponse.newBuilder()
+ .setBitdepth(bitDepthProto)
+ .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-depth", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitrate/CreateBitRateHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/CreateBitRateHandler.java
new file mode 100644
index 0000000..cfa9d2b
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/CreateBitRateHandler.java
@@ -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()));
+ }
+ }
+}
+
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitrate/DeleteBitRateHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/DeleteBitRateHandler.java
new file mode 100644
index 0000000..35c520e
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/DeleteBitRateHandler.java
@@ -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());
+ }
+ }
+ }
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateByIdHandler.java
new file mode 100644
index 0000000..a88893b
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateByIdHandler.java
@@ -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 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()));
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateHandler.java
new file mode 100644
index 0000000..87c6ca3
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/GetBitRateHandler.java
@@ -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 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()));
+ }
+ }
+}
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/bitrate/UpdateBitRateHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/UpdateBitRateHandler.java
new file mode 100644
index 0000000..f5e6dc9
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/bitrate/UpdateBitRateHandler.java
@@ -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 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()));
+ }
+ }
+}
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/java/com/mediamanager/service/delegate/handler/genre/CreateGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/genre/CreateGenreHandler.java
new file mode 100644
index 0000000..569b119
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/CreateGenreHandler.java
@@ -0,0 +1,62 @@
+package com.mediamanager.service.delegate.handler.genre;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.GenreMapper;
+import com.mediamanager.model.Genre;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.GenreMessages;
+import com.mediamanager.service.delegate.ActionHandler;
+import com.mediamanager.service.delegate.annotation.Action;
+import com.mediamanager.service.genre.GenreService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+@Action("genre.create")
+public class CreateGenreHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(CreateGenreHandler.class);
+
+ private final GenreService genreService;
+
+ public CreateGenreHandler(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+ try {
+ // 1. Parse protobuf request
+ GenreMessages.CreateGenreRequest createRequest =
+ GenreMessages.CreateGenreRequest.parseFrom(requestPayload);
+
+ // 2. Chama service (lógica de negócio)
+ Genre genre = genreService.createGenre(createRequest.getName());
+
+ // 3. Converte entity para protobuf
+ GenreMessages.Genre genreProto = GenreMapper.toProtobuf(genre);
+
+ // 4. Cria response protobuf
+ GenreMessages.CreateGenreResponse createResponse =
+ GenreMessages.CreateGenreResponse.newBuilder()
+ .setGenre(genreProto)
+ .build();
+
+ // 5. Retorna
+ 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 genre", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/genre/DeleteGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/genre/DeleteGenreHandler.java
new file mode 100644
index 0000000..bffdb1e
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/DeleteGenreHandler.java
@@ -0,0 +1,72 @@
+package com.mediamanager.service.delegate.handler.genre;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.GenreMessages;
+import com.mediamanager.service.delegate.ActionHandler;
+import com.mediamanager.service.delegate.annotation.Action;
+import com.mediamanager.service.genre.GenreService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+@Action("genre.delete")
+public class DeleteGenreHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(DeleteGenreHandler.class);
+
+ private final GenreService genreService;
+
+ public DeleteGenreHandler(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+ try {
+ // 1. Parse protobuf request
+ GenreMessages.DeleteGenreRequest deleteRequest =
+ GenreMessages.DeleteGenreRequest.parseFrom(requestPayload);
+
+ int id = deleteRequest.getId();
+
+ // 2. Deleta via service
+ boolean success = genreService.deleteGenre(id);
+
+ // 3. Cria response
+ GenreMessages.DeleteGenreResponse deleteResponse;
+
+ if (success) {
+ deleteResponse = GenreMessages.DeleteGenreResponse.newBuilder()
+ .setSuccess(true)
+ .setMessage("Genre deleted successfully")
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(deleteResponse.toByteString());
+ } else {
+ deleteResponse = GenreMessages.DeleteGenreResponse.newBuilder()
+ .setSuccess(false)
+ .setMessage("Genre not found")
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(deleteResponse.toByteString());
+ }
+
+ } catch (Exception e) {
+ logger.error("Error deleting genre", e);
+
+ GenreMessages.DeleteGenreResponse deleteResponse =
+ GenreMessages.DeleteGenreResponse.newBuilder()
+ .setSuccess(false)
+ .setMessage("Error: " + e.getMessage())
+ .build();
+
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(deleteResponse.toByteString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreByIdHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreByIdHandler.java
new file mode 100644
index 0000000..4dc4c71
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreByIdHandler.java
@@ -0,0 +1,66 @@
+package com.mediamanager.service.delegate.handler.genre;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.GenreMapper;
+import com.mediamanager.model.Genre;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.GenreMessages;
+import com.mediamanager.service.delegate.ActionHandler;
+import com.mediamanager.service.delegate.annotation.Action;
+import com.mediamanager.service.genre.GenreService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Optional;
+
+@Action("genre.getById")
+public class GetGenreByIdHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetGenreByIdHandler.class);
+
+ private final GenreService genreService;
+
+ public GetGenreByIdHandler(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+ try {
+ // 1. Parse protobuf request
+ GenreMessages.GetGenreByIdRequest getByIdRequest =
+ GenreMessages.GetGenreByIdRequest.parseFrom(requestPayload);
+
+ int id = getByIdRequest.getId();
+
+ // 2. Busca via service
+ Optional genreOpt = genreService.getGenreById(id);
+
+ if (genreOpt.isEmpty()) {
+ logger.warn("Genre not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("Genre not found"));
+ }
+
+ // 3. Converte para protobuf
+ GenreMessages.Genre genreProto = GenreMapper.toProtobuf(genreOpt.get());
+
+ GenreMessages.GetGenreByIdResponse getByIdResponse =
+ GenreMessages.GetGenreByIdResponse.newBuilder()
+ .setGenre(genreProto)
+ .build();
+
+ // 4. Retorna
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getByIdResponse.toByteString());
+
+ } catch (Exception e) {
+ logger.error("Error getting genre by ID", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreHandler.java
new file mode 100644
index 0000000..068b44c
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreHandler.java
@@ -0,0 +1,56 @@
+package com.mediamanager.service.delegate.handler.genre;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.GenreMapper;
+import com.mediamanager.model.Genre;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.GenreMessages;
+import com.mediamanager.service.delegate.ActionHandler;
+import com.mediamanager.service.delegate.annotation.Action;
+import com.mediamanager.service.genre.GenreService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.List;
+
+@Action("genre.getAll")
+public class GetGenreHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(GetGenreHandler.class);
+
+ private final GenreService genreService;
+
+ public GetGenreHandler(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+ try {
+ // 1. Busca todos os genres via service
+ List genres = genreService.getAllGenres();
+
+ // 2. Converte cada Genre para protobuf
+ GenreMessages.GetGenresResponse.Builder responseBuilder =
+ GenreMessages.GetGenresResponse.newBuilder();
+
+ for (Genre genre : genres) {
+ GenreMessages.Genre genreProto = GenreMapper.toProtobuf(genre);
+ responseBuilder.addGenres(genreProto);
+ }
+
+ GenreMessages.GetGenresResponse getGenresResponse = responseBuilder.build();
+
+ // 3. Retorna
+ return TransportProtocol.Response.newBuilder()
+ .setPayload(getGenresResponse.toByteString());
+
+ } catch (Exception e) {
+ logger.error("Error getting genres", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/delegate/handler/genre/UpdateGenreHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/genre/UpdateGenreHandler.java
new file mode 100644
index 0000000..d0b54d1
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/UpdateGenreHandler.java
@@ -0,0 +1,73 @@
+package com.mediamanager.service.delegate.handler.genre;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.mediamanager.mapper.GenreMapper;
+import com.mediamanager.model.Genre;
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.protocol.messages.GenreMessages;
+import com.mediamanager.service.delegate.ActionHandler;
+import com.mediamanager.service.delegate.annotation.Action;
+import com.mediamanager.service.genre.GenreService;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Optional;
+
+@Action("genre.update")
+public class UpdateGenreHandler implements ActionHandler {
+ private static final Logger logger = LogManager.getLogger(UpdateGenreHandler.class);
+
+ private final GenreService genreService;
+
+ public UpdateGenreHandler(GenreService genreService) {
+ this.genreService = genreService;
+ }
+
+ @Override
+ public TransportProtocol.Response.Builder handle(ByteString requestPayload)
+ throws InvalidProtocolBufferException {
+ try {
+ // 1. Parse protobuf request
+ GenreMessages.UpdateGenreRequest updateRequest =
+ GenreMessages.UpdateGenreRequest.parseFrom(requestPayload);
+
+ int id = updateRequest.getId();
+ String newName = updateRequest.getName();
+
+ // 2. Atualiza via service
+ Optional genreOpt = genreService.updateGenre(id, newName);
+
+ if (genreOpt.isEmpty()) {
+ logger.warn("Genre not found with ID: {}", id);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(404)
+ .setPayload(ByteString.copyFromUtf8("Genre not found"));
+ }
+
+ // 3. Converte para protobuf
+ GenreMessages.Genre genreProto = GenreMapper.toProtobuf(genreOpt.get());
+
+ GenreMessages.UpdateGenreResponse updateResponse =
+ GenreMessages.UpdateGenreResponse.newBuilder()
+ .setGenre(genreProto)
+ .build();
+
+ // 4. Retorna
+ 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 genre", e);
+ return TransportProtocol.Response.newBuilder()
+ .setStatusCode(500)
+ .setPayload(ByteString.copyFromUtf8("Error: " + e.getMessage()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/genre/GenreService.java b/src/main/java/com/mediamanager/service/genre/GenreService.java
new file mode 100644
index 0000000..f0acf70
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/genre/GenreService.java
@@ -0,0 +1,88 @@
+package com.mediamanager.service.genre;
+
+import com.mediamanager.model.Genre;
+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;
+
+/**
+ * Service para lógica de negócio relacionada a Genre
+ */
+public class GenreService {
+ private static final Logger logger = LogManager.getLogger(GenreService.class);
+
+ private final GenreRepository genreRepository;
+
+ public GenreService(GenreRepository genreRepository) {
+ this.genreRepository = genreRepository;
+ }
+
+ /**
+ * Cria um novo genre
+ */
+ public Genre createGenre(String name) {
+ logger.info("Creating genre: {}", name);
+
+ // Aqui poderia ter validações de negócio
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("Genre name cannot be empty");
+ }
+
+ Genre genre = new Genre();
+ genre.setName(name.trim());
+
+ return genreRepository.save(genre);
+ }
+
+ /**
+ * Busca todos os genres
+ */
+ public List getAllGenres() {
+ logger.info("Getting all genres");
+ return genreRepository.findAll();
+ }
+
+ /**
+ * Busca genre por ID
+ */
+ public Optional getGenreById(Integer id) {
+ logger.info("Getting genre by ID: {}", id);
+ return genreRepository.findById(id);
+ }
+
+ /**
+ * Atualiza um genre existente
+ */
+ public Optional updateGenre(Integer id, String name) {
+ logger.info("Updating genre ID {}: {}", id, name);
+
+ // Validação
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("Genre name cannot be empty");
+ }
+
+ Optional existingGenre = genreRepository.findById(id);
+
+ if (existingGenre.isEmpty()) {
+ logger.warn("Genre not found with ID: {}", id);
+ return Optional.empty();
+ }
+
+ Genre genre = existingGenre.get();
+ genre.setName(name.trim());
+
+ Genre updated = genreRepository.update(genre);
+ return Optional.of(updated);
+ }
+
+ /**
+ * Deleta um genre por ID
+ */
+ public boolean deleteGenre(Integer id) {
+ logger.info("Deleting genre ID: {}", id);
+ return genreRepository.deleteById(id);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/mediamanager/service/ipc/IPCManager.java b/src/main/java/com/mediamanager/service/ipc/IPCManager.java
new file mode 100644
index 0000000..7fe7541
--- /dev/null
+++ b/src/main/java/com/mediamanager/service/ipc/IPCManager.java
@@ -0,0 +1,337 @@
+package com.mediamanager.service.ipc;
+
+import com.mediamanager.protocol.TransportProtocol;
+import com.mediamanager.service.delegate.DelegateActionManager;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+
+import java.io.IOException;
+import java.net.StandardProtocolFamily;
+import java.net.UnixDomainSocketAddress;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class IPCManager {
+ private final Properties configuration;
+ private static final Logger logger = LogManager.getLogger(IPCManager.class);
+ private final DelegateActionManager actionManager;
+
+ private Path socketPath;
+ private UnixDomainSocketAddress socketAddress;
+ private ServerSocketChannel serverChannel;
+ private ExecutorService clientThreadPool;
+ private final AtomicBoolean running = new AtomicBoolean(false);
+ private final ConcurrentHashMap activeClients = new ConcurrentHashMap<>();
+ private final AtomicInteger clientIdCounter = new AtomicInteger(0);
+
+
+ public IPCManager(Properties config, DelegateActionManager actionManager){
+ configuration = config;
+ this.actionManager = actionManager;
+ logger.debug("IPCManager created with configuration:");
+
+
+ }
+ public void init() throws Exception {
+ logger.info("Initializing IPC connection...");
+ validateConfiguration();
+ socketPath = Path.of(configuration.getProperty("ipc.socket.path")).resolve("mediamanager.sock");
+
+ if (Files.exists(socketPath)) {
+ logger.warn("Socket file already exists at: {}", socketPath);
+ logger.info("Deleting existing socket...");
+ Files.deleteIfExists(socketPath);
+ }
+
+ Path parentDir = socketPath.getParent();
+ if (parentDir != null && !Files.exists(parentDir)) {
+ logger.info("Creating parent directory for socket: {}", parentDir);
+ Files.createDirectories(parentDir);
+ }
+
+ try {
+ socketAddress = UnixDomainSocketAddress.of(socketPath);
+ logger.debug("Socket address created");
+
+ serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
+ serverChannel.bind(socketAddress);
+ logger.info("Server bound to socket - file created at: {}", socketPath);
+
+ // ESTA É A MUDANÇA CRÍTICA
+ // Configura o canal para modo não-bloqueante
+ // Isso faz accept() retornar null imediatamente se não houver cliente
+ // ao invés de bloquear esperando indefinidamente
+ serverChannel.configureBlocking(false);
+ logger.debug("Server channel configured for non-blocking mode");
+
+ Set perms = PosixFilePermissions.fromString("rw-------");
+ Files.setPosixFilePermissions(socketPath, perms);
+ logger.debug("Socket permissions set to: rw-------");
+
+ clientThreadPool = Executors.newCachedThreadPool(runnable -> {
+ Thread thread = new Thread(runnable);
+ thread.setName("IPC-Client-Handler-" + thread.getId());
+ thread.setDaemon(true);
+ return thread;
+ });
+ logger.debug("Client thread pool created");
+
+ running.set(true);
+
+ Thread serverThread = new Thread(this::acceptConnectionsLoop, "IPC-Server-Accept-Thread");
+ serverThread.setDaemon(true);
+ serverThread.start();
+ logger.info("Server thread started - accepting connections");
+
+ logger.info("IPC server initialized successfully on {}", socketPath.toAbsolutePath());
+
+ } catch (IOException e) {
+ logger.error("Failed to initialize IPC server: {}", e.getMessage());
+ throw new Exception("Failed to initialize IPC server: " + e.getMessage(), e);
+ }
+ }
+ private void validateConfiguration() throws Exception {
+ String[] requiredProperties = {
+ "ipc.socket.path"
+ };
+ for (String property : requiredProperties) {
+ if (configuration.getProperty(property) == null) {
+ throw new Exception("Missing required configuration property: " + property);
+ }
+ }
+ logger.debug("IPC configuration validated successfully");
+ }
+
+ public Path getSocketPath(){
+ return socketPath;
+ }
+
+ public void close() throws Exception {
+ if(!running.get()){
+ logger.warn("IPC connection is already closed");
+ }
+
+
+ logger.info("Closing IPC connection...");
+
+ running.set(false);
+ if (serverChannel != null && serverChannel.isOpen()) {
+ serverChannel.close();
+ logger.debug("Server channel closed");
+ }
+
+ if (clientThreadPool != null) {
+ clientThreadPool.shutdown();
+ try {
+ if (!clientThreadPool.awaitTermination(30, TimeUnit.SECONDS)) {
+ logger.warn("Some client handlers did not finish in time, forcing shutdown");
+ clientThreadPool.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ logger.error("Interrupted while waiting for client handlers", e);
+ clientThreadPool.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ if (socketPath != null && Files.exists(socketPath)) {
+ Files.deleteIfExists(socketPath);
+ logger.info("Socket file deleted successfully");
+ }
+
+ logger.info("IPC server closed successfully");
+ }
+
+ private void acceptConnectionsLoop() {
+ logger.info("Preparing to accept connections...");
+
+ while (running.get()) {
+ try {
+ // Em modo não-bloqueante, accept() retorna imediatamente
+ // Se há um cliente esperando, retorna o SocketChannel
+ // Se não há cliente, retorna null
+ SocketChannel clientChannel = serverChannel.accept();
+
+ if (clientChannel != null) {
+ // Um cliente realmente se conectou!
+ int clientId = clientIdCounter.incrementAndGet();
+ logger.info("Client {} connected", clientId);
+
+ ClientHandler handler = new ClientHandler(clientId, clientChannel);
+ activeClients.put(clientId, handler);
+
+ clientThreadPool.submit(() -> {
+ try {
+ handler.handle();
+ } finally {
+ activeClients.remove(clientId);
+ logger.info("Client {} disconnected", clientId);
+ }
+ });
+ } else {
+ // Nenhum cliente conectado no momento
+ // Dorme por um curto período antes de verificar novamente
+ // Isso evita consumir CPU desnecessariamente em um loop vazio
+ Thread.sleep(1); // 1 milissegundos
+ }
+
+ } catch (InterruptedException e) {
+ // Thread foi interrompida, provavelmente durante shutdown
+ logger.debug("Accept loop interrupted");
+ break;
+
+ } catch (IOException e) {
+ // Erros de I/O reais devem ser logados
+ if (running.get()) {
+ logger.error("Error accepting client connection", e);
+ }
+ break;
+ }
+ }
+
+ logger.info("Connection loop stopped gracefully");
+ }
+
+
+ private class ClientHandler {
+ private final int clientId;
+ private final SocketChannel channel;
+
+ public ClientHandler(int clientId, SocketChannel channel) {
+ this.clientId = clientId;
+ this.channel = channel;
+ }
+
+ /**
+ * Método principal que processa a comunicação com o cliente.
+ * Aqui é onde vamos ler mensagens JSON, processá-las, e enviar respostas.
+ */
+ public void handle() {
+ logger.debug("Client {} handler thread started", clientId);
+
+ try {
+ // LOOP: processa múltiplas requests na mesma conexão
+ while (channel.isOpen()) {
+ TransportProtocol.Request request = readRequest(channel);
+
+ if (request == null) {
+ // Cliente desconectou gracefully
+ logger.info("Client {} disconnected (end of stream)", clientId);
+ break;
+ }
+
+ logger.info("Client {} sent request {}", clientId, request.getRequestId());
+
+ // Processa usando o DelegateActionManager
+ TransportProtocol.Response response = actionManager.ProcessedRequest(request);
+
+ // Envia resposta de volta
+ writeResponse(channel, response);
+ logger.info("Client {} response sent", clientId);
+
+ // Verifica se é comando CLOSE
+ String connectionHeader = response.getHeadersOrDefault("Connection", "");
+ if ("close".equals(connectionHeader)) {
+ logger.info("Client {} requested connection close", clientId);
+ break; // Sai do loop e fecha
+ }
+ }
+
+ } catch (IOException e) {
+ if (channel.isOpen()) {
+ logger.error("IO error handling client {}", clientId, e);
+ } else {
+ logger.debug("Client {} connection closed by peer", clientId);
+ }
+ } catch (Exception e) {
+ logger.error("Unexpected error handling client {}", clientId, e);
+ } finally {
+ try {
+ if (channel.isOpen()) {
+ channel.close();
+ }
+ logger.debug("Client {} channel closed", clientId);
+ } catch (IOException e) {
+ logger.error("Error closing client {} channel", clientId, e);
+ }
+ }
+ }
+ private TransportProtocol.Request readRequest(SocketChannel channel) throws IOException {
+ // Primeiro, lê o tamanho da mensagem (4 bytes = int32)
+ java.nio.ByteBuffer sizeBuffer = java.nio.ByteBuffer.allocate(4);
+ int bytesRead = 0;
+
+ while (bytesRead < 4) {
+ int read = channel.read(sizeBuffer);
+ if (read == -1) {
+ logger.debug("Client disconnected before sending size");
+ return null;
+ }
+ bytesRead += read;
+ }
+
+ sizeBuffer.flip();
+ int messageSize = sizeBuffer.getInt();
+ logger.debug("Expecting message of {} bytes", messageSize);
+
+ // Validação básica de segurança
+ if (messageSize <= 0 || messageSize > 1024 * 1024) { // Max 1MB
+ throw new IOException("Invalid message size: " + messageSize);
+ }
+
+ // Agora lê a mensagem completa
+ java.nio.ByteBuffer messageBuffer = java.nio.ByteBuffer.allocate(messageSize);
+ bytesRead = 0;
+
+ while (bytesRead < messageSize) {
+ int read = channel.read(messageBuffer);
+ if (read == -1) {
+ throw new IOException("Client disconnected while reading message");
+ }
+ bytesRead += read;
+ }
+
+ messageBuffer.flip();
+
+ // Deserializa o Protocol Buffers
+ byte[] messageBytes = new byte[messageSize];
+ messageBuffer.get(messageBytes);
+
+ return TransportProtocol.Request.parseFrom(messageBytes);
+ }
+
+ private void writeResponse(SocketChannel channel, TransportProtocol.Response response) throws IOException {
+ byte[] messageBytes = response.toByteArray();
+ int messageSize = messageBytes.length;
+
+ logger.debug("Writing response of {} bytes", messageSize);
+
+ java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(4 + messageSize);
+ buffer.putInt(messageSize);
+ buffer.put(messageBytes);
+ buffer.flip();
+
+ while (buffer.hasRemaining()) {
+ channel.write(buffer);
+ }
+
+ logger.debug("Response written successfully");
+ }
+ }
+}
+
+
+
diff --git a/src/main/proto/artist.proto b/src/main/proto/artist.proto
new file mode 100644
index 0000000..1f68272
--- /dev/null
+++ b/src/main/proto/artist.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+option java_package = "com.mediamanager.protocol.messages";
+option java_outer_classname = "ArtistMessages";
+
+package mediamanager.messages;
+
+message Artist {
+ int32 id = 1;
+ string name = 2;
+}
+
+message CreateArtistRequest {
+ string name = 1;
+}
+
+message CreateArtistResponse {
+ Artist artist = 1;
+}
+
+message GetArtistsRequest {
+
+}
+
+message GetArtistsResponse {
+ repeated Artist artists = 1;
+}
+
+message GetArtistByIdRequest {
+ int32 id = 1;
+}
+
+message GetArtistByIdResponse {
+ Artist artist = 1;
+}
+
+message UpdateArtistRequest {
+ int32 id = 1;
+ string name = 2; // Novo nome
+}
+
+message UpdateArtistResponse {
+ Artist artist = 1;
+}
+
+message DeleteArtistRequest {
+ int32 id = 1;
+}
+
+message DeleteArtistResponse {
+ bool success = 1;
+ string message = 2;
+}
diff --git a/src/main/proto/bitdepth.proto b/src/main/proto/bitdepth.proto
new file mode 100644
index 0000000..571dc9a
--- /dev/null
+++ b/src/main/proto/bitdepth.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+option java_package = "com.mediamanager.protocol.messages";
+option java_outer_classname = "BitDepthMessages";
+
+package mediamanager.messages;
+
+message BitDepth {
+ int32 id = 1;
+ string value = 2;
+}
+
+message CreateBitDepthRequest {
+ string value = 1;
+}
+
+message CreateBitDepthResponse {
+ BitDepth bitdepth = 1;
+}
+
+message GetBitDepthsRequest {
+
+}
+
+message GetBitDepthsResponse {
+ repeated BitDepth bitdepths = 1;
+}
+
+message GetBitDepthByIdRequest {
+ int32 id = 1;
+}
+
+message GetBitDepthByIdResponse {
+ BitDepth bitdepth = 1;
+}
+
+message UpdateBitDepthRequest {
+ int32 id = 1;
+ string value = 2; // Novo nome
+}
+
+message UpdateBitDepthResponse {
+ BitDepth bitdepth = 1;
+}
+
+message DeleteBitDepthRequest {
+ int32 id = 1;
+}
+
+message DeleteBitDepthResponse {
+ bool success = 1;
+ string message = 2;
+}
diff --git a/src/main/proto/bitrate.proto b/src/main/proto/bitrate.proto
new file mode 100644
index 0000000..4f69ea3
--- /dev/null
+++ b/src/main/proto/bitrate.proto
@@ -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;
+}
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;
+}
diff --git a/src/main/proto/genre.proto b/src/main/proto/genre.proto
new file mode 100644
index 0000000..b059b89
--- /dev/null
+++ b/src/main/proto/genre.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+option java_package = "com.mediamanager.protocol.messages";
+option java_outer_classname = "GenreMessages";
+
+package mediamanager.messages;
+
+message Genre {
+ int32 id = 1;
+ string name = 2;
+}
+
+message CreateGenreRequest {
+ string name = 1;
+}
+
+message CreateGenreResponse {
+ Genre genre = 1;
+}
+
+message GetGenresRequest {
+
+}
+
+message GetGenresResponse {
+ repeated Genre genres = 1;
+}
+
+message GetGenreByIdRequest {
+ int32 id = 1;
+}
+
+message GetGenreByIdResponse {
+ Genre genre = 1;
+}
+
+message UpdateGenreRequest {
+ int32 id = 1;
+ string name = 2; // Novo nome
+}
+
+message UpdateGenreResponse {
+ Genre genre = 1; // Genre atualizado
+}
+
+message DeleteGenreRequest {
+ int32 id = 1;
+}
+
+message DeleteGenreResponse {
+ bool success = 1;
+ string message = 2;
+}
diff --git a/src/main/proto/messages.proto b/src/main/proto/messages.proto
new file mode 100644
index 0000000..106e59e
--- /dev/null
+++ b/src/main/proto/messages.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+option java_package = "com.mediamanager.protocol";
+option java_outer_classname = "TransportProtocol";
+
+package mediamanager;
+
+message Request {
+ string request_id = 1;
+ bytes payload = 2;
+ map headers = 3;
+}
+
+message Response {
+ string request_id = 1;
+ int32 status_code = 2;
+ bytes payload = 3;
+ map headers = 4;
+}
\ No newline at end of file
diff --git a/src/main/proto/test.proto b/src/main/proto/test.proto
new file mode 100644
index 0000000..00330cd
--- /dev/null
+++ b/src/main/proto/test.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+option java_package = "com.mediamanager.protocol";
+option java_outer_classname = "TestProtocol";
+
+package mediamanager.test;
+
+message EchoCommand {
+ string message = 1;
+}
+
+message EchoResponse {
+ string message = 1;
+ int64 server_timestamp = 2;
+}
+
+message HeartbeatCommand {
+ int64 client_timestamp = 1;
+}
+
+message HeartbeatResponse {
+ int64 client_timestamp = 1;
+ int64 server_timestamp = 2;
+}
+message CloseCommand {
+ // Vazio - apenas sinaliza fechamento
+}
+message CloseResponse {
+ string message = 1;
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/config.properties.example
similarity index 92%
rename from src/main/resources/application.properties
rename to src/main/resources/config.properties.example
index fbef11a..0991905 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/config.properties.example
@@ -21,3 +21,8 @@ hibernate.format_sql=true
ipc.pipe.name=mediamanager-pipe
ipc.pipe.path=/tmp/mediamanager
ipc.buffer.size=8192
+runtype=local
+ipc.socket.path=/tmp/mediamanager
+
+
+
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 29d32dc..a9f3f84 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -1,12 +1,13 @@
-
+
-
+
+ filePattern="logs/mediamanager-%d{yyyy-MM-dd}-%i.log"
+ immediateFlush="true">
@@ -17,17 +18,17 @@
-
+
-
+
-
+