From b715bb1bd342eb8a4885429adedc85fd8b92ff22 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sat, 29 Nov 2025 07:54:46 -0300 Subject: [PATCH 1/3] Add `@Action` annotation and `ServiceLocator` for improved handler registration - Introduce `@Action` annotation to simplify action handler identification and tagging. - Add `ServiceLocator` for dynamic service registration and retrieval. - Annotate handlers (`CreateGenreHandler`, `GetGenreHandler`, `UpdateGenreHandler`, `DeleteGenreHandler`, etc.) with corresponding actions. --- .../service/delegate/ServiceLocator.java | 45 +++++++++++++++++++ .../service/delegate/annotation/Action.java | 13 ++++++ .../delegate/handler/CloseHandler.java | 2 + .../service/delegate/handler/EchoHandler.java | 2 + .../delegate/handler/HeartbeatHandler.java | 2 + .../handler/genre/CreateGenreHandler.java | 2 + .../handler/genre/DeleteGenreHandler.java | 2 + .../handler/genre/GetGenreByIdHandler.java | 2 + .../handler/genre/GetGenreHandler.java | 2 + .../handler/genre/UpdateGenreHandler.java | 2 + 10 files changed, 74 insertions(+) create mode 100644 src/main/java/com/mediamanager/service/delegate/ServiceLocator.java create mode 100644 src/main/java/com/mediamanager/service/delegate/annotation/Action.java 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 index de59bf3..9e9c658 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/CloseHandler.java @@ -6,9 +6,11 @@ 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); diff --git a/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java index 1e7ece9..657c2e7 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/EchoHandler.java @@ -6,9 +6,11 @@ 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); diff --git a/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java index 20e3d6d..d79270c 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/HeartbeatHandler.java @@ -6,9 +6,11 @@ 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); 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 index 93b530a..569b119 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/genre/CreateGenreHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/CreateGenreHandler.java @@ -7,10 +7,12 @@ 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); 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 index 61f90df..bffdb1e 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/genre/DeleteGenreHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/DeleteGenreHandler.java @@ -5,10 +5,12 @@ 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); 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 index 77ce9e3..9dfb2db 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreByIdHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreByIdHandler.java @@ -7,12 +7,14 @@ 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); 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 index 1cb3c94..068b44c 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/GetGenreHandler.java @@ -7,12 +7,14 @@ 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); 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 index 919f50c..d0b54d1 100644 --- a/src/main/java/com/mediamanager/service/delegate/handler/genre/UpdateGenreHandler.java +++ b/src/main/java/com/mediamanager/service/delegate/handler/genre/UpdateGenreHandler.java @@ -7,12 +7,14 @@ 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); From f87d6b1b53fc9bc86fb8889c5bac00c4346ca2a4 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Sat, 29 Nov 2025 08:26:58 -0300 Subject: [PATCH 2/3] Refactor `DelegateActionManager` for dynamic handler registration - Replace manual handler registration with automatic scanning and registration of handlers annotated with `@Action`. - Introduce `ServiceLocator` to enable dependency injection for dynamically instantiated handlers. - Add `initializeServices` to centralize service initialization and registration. - Enhance error handling and logging for handler instantiation and registration processes. --- .../delegate/DelegateActionManager.java | 156 ++++++++++++++++-- 1 file changed, 139 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index 2221236..3e35e4b 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -3,46 +3,59 @@ package com.mediamanager.service.delegate; import com.google.protobuf.ByteString; import com.mediamanager.protocol.TransportProtocol; import com.mediamanager.repository.GenreRepository; -import com.mediamanager.service.delegate.handler.CloseHandler; -import com.mediamanager.service.delegate.handler.EchoHandler; -import com.mediamanager.service.delegate.handler.HeartbeatHandler; -import com.mediamanager.service.delegate.handler.genre.*; +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; - private final GenreService genreService; + public DelegateActionManager(EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; + this.serviceLocator = new ServiceLocator(); + + initializeServices(); + - GenreRepository genreRepository = new GenreRepository(entityManagerFactory); - this.genreService = new GenreService(genreRepository); logger.debug("DelegateActionManager created"); this.handlerRegistry = new HashMap<>(); - registerHandlers(); + autoRegisterHandlers(); + } - private void registerHandlers() { - handlerRegistry.put("echo",new EchoHandler()); - handlerRegistry.put("heartbeat",new HeartbeatHandler()); - handlerRegistry.put("close", new CloseHandler()); - handlerRegistry.put("create_genre", new CreateGenreHandler(genreService)); - handlerRegistry.put("get_genres", new GetGenreHandler(genreService)); - handlerRegistry.put("get_genre_by_id", new GetGenreByIdHandler(genreService)); - handlerRegistry.put("update_genre", new UpdateGenreHandler(genreService)); - handlerRegistry.put("delete_genre", new DeleteGenreHandler(genreService)); + private void initializeServices() { + logger.info("Initializing services..."); + + + GenreRepository genreRepository = new GenreRepository(entityManagerFactory); + GenreService genreService = new GenreService(genreRepository); + + + serviceLocator.register(GenreService.class, genreService); + + + serviceLocator.logRegisteredServices(); + + logger.info("Services initialized successfully"); } + + public void start(){ logger.info("DelegateActionManager started"); } @@ -51,6 +64,115 @@ public class DelegateActionManager { logger.info("DelegateActionManager stopped"); } + @SuppressWarnings("unchecked") + private ActionHandler instantiateHandler(Class clazz) throws Exception { + logger.debug("Attempting to instantiate handler: {}", clazz.getSimpleName()); + + + Constructor[] constructors = clazz.getDeclaredConstructors(); + + + for (Constructor constructor : constructors) { + + Class[] paramTypes = constructor.getParameterTypes(); + + + if (paramTypes.length == 0) { + logger.debug("Using no-arg constructor for {}", clazz.getSimpleName()); + return (ActionHandler) constructor.newInstance(); + } + + + 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("Successfully resolved {} dependencies 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); From a5bd6e2c398babde938fedf2243e01e24ddabe7c Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Miranda Date: Sat, 29 Nov 2025 09:52:54 -0300 Subject: [PATCH 3/3] Update src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../service/delegate/DelegateActionManager.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java index 3e35e4b..fa47150 100644 --- a/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java +++ b/src/main/java/com/mediamanager/service/delegate/DelegateActionManager.java @@ -72,17 +72,17 @@ public class DelegateActionManager { Constructor[] constructors = clazz.getDeclaredConstructors(); + 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(); - if (paramTypes.length == 0) { - logger.debug("Using no-arg constructor for {}", clazz.getSimpleName()); - return (ActionHandler) constructor.newInstance(); - } - - Object[] params = new Object[paramTypes.length]; boolean allDependenciesResolved = true; @@ -105,9 +105,8 @@ public class DelegateActionManager { if (allDependenciesResolved) { - logger.debug("Successfully resolved {} dependencies for {}", - paramTypes.length, - clazz.getSimpleName()); + logger.debug("Using constructor with {} params for {}", + paramTypes.length, clazz.getSimpleName()); return (ActionHandler) constructor.newInstance(params); } }