// Path: services-core/src/main/java/io/plumery/core/ActionHandler.java
// public interface ActionHandler<T extends Action>  {
//     public void handle(T action);
// }
// 
// Path: services-core/src/main/java/io/plumery/core/Event.java
// public abstract class Event implements Action {
//     public int version;
//     public ID id;
// }
// 
// Path: services-core/src/main/java/io/plumery/core/infrastructure/EventPublisher.java
// public interface EventPublisher {
//     <T extends Event> void publish(String streamName, T event);
// }
// 
// Path: services-infrastructure-messaging/src/main/java/io/plumery/messaging/ActionHandlerResolver.java
// public class ActionHandlerResolver {
//     private static final ThreadLocal<ActionHandlerResolver> CURRENT = new ThreadLocal<>();
// 
//     public static ActionHandlerResolver getCurrent() {
//         return CURRENT.get();
//     }
// 
//     public static void setCurrent(ActionHandlerResolver resolver) {
//         CURRENT.set(resolver);
//     }
// 
//     private Set<ActionHandler> actionHandlers;
// 
//     private ActionHandlerResolver() {
//     }
// 
//     public void setActionHandlers(Set<ActionHandler> actionHandlers) {
//         this.actionHandlers = actionHandlers;
//     }
// 
//     public List<ActionHandler> findHandlersFor(String action) {
//         List<ActionHandler> list = new ArrayList<>();
// 
//         for (ActionHandler actionHandler : actionHandlers) {
//             Class<?> actionClass = getHandledActionType(actionHandler.getClass());
// 
//             if (actionClass.getSimpleName().equals(action)) {
//                 list.add(actionHandler);
//             }
//         }
// 
//         return list;
//     }
// 
//     public Class<?> getHandledActionType(Class<?> clazz) {
//         Type[] genericInterfaces = clazz.getGenericInterfaces();
// 
//         ParameterizedType type = findByRawType(genericInterfaces, CommandHandler.class);
//         if (type == null) {
//             type = findByRawType(genericInterfaces, EventHandler.class);
//         }
// 
//         return (Class<?>) type.getActualTypeArguments()[0];
//     }
// 
//     private ParameterizedType findByRawType(Type[] genericInterfaces, Class<?> expectedRawType) {
//         for (Type type : genericInterfaces) {
//             if (type instanceof ParameterizedType) {
//                 ParameterizedType parametrized = (ParameterizedType) type;
// 
//                 if (expectedRawType.equals(parametrized.getRawType())) {
//                     return parametrized;
//                 }
//             }
//         }
// 
//         return null;
//     }
// 
//     public List<String> getSupportedActions() {
//         List<String> actions = new ArrayList<>();
//         for (ActionHandler actionHandler : actionHandlers) {
//             Class<?> actionClass = getHandledActionType(actionHandler.getClass());
//             String action = actionClass.getSimpleName();
// 
//             actions.add(action);
//         }
// 
//         return actions;
//     }
// 
//     public static ActionHandlerResolver newInstance() {
//         ActionHandlerResolver resolver = new ActionHandlerResolver();
//         setCurrent(resolver);
// 
//         return resolver;
//     }
// 
//     public <T extends ActionHandler> void registerActionHandler(T actionHandler) {
//         if (actionHandlers == null) {
//             actionHandlers = new HashSet<>();
//         }
// 
//         actionHandlers.add(actionHandler);
//     }
// }


import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.reflect.TypeToken;
import io.plumery.core.ActionHandler;
import io.plumery.core.Event;
import io.plumery.core.infrastructure.EventPublisher;
import io.plumery.messaging.ActionHandlerResolver;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
package io.plumery.messaging.local;



public class LocalEventPublisher implements EventPublisher {
    private final ActionHandlerResolver resolverProvider;

    /**
     * Inject lazy LocalActionHandlerResolver provider in order to be able using EventPublisher in action handlers (directly or indirectly);
     * @param resolverProvider
     */
    public LocalEventPublisher(ActionHandlerResolver resolverProvider) {
        this.resolverProvider = resolverProvider;
    }

    @Override
    public <T extends Event> void publish(String streamName, T event) {
        List<ActionHandler> handlers = resolverProvider.findHandlersFor(event.getClass().getSimpleName());

        if(handlers != null && handlers.size() > 0) {
            for (ActionHandler<T> handler : handlers) {
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    Method handleMethod = getHandlingMethod(handler);
// Path: services-core/src/main/java/io/plumery/core/ActionHandler.java
// public interface ActionHandler<T extends Action>  {
//     public void handle(T action);
// }
// 
// Path: services-core/src/main/java/io/plumery/core/Event.java
// public abstract class Event implements Action {
//     public int version;
//     public ID id;
// }
// 
// Path: services-core/src/main/java/io/plumery/core/infrastructure/EventPublisher.java
// public interface EventPublisher {
//     <T extends Event> void publish(String streamName, T event);
// }
// 
// Path: services-infrastructure-messaging/src/main/java/io/plumery/messaging/ActionHandlerResolver.java
// public class ActionHandlerResolver {
//     private static final ThreadLocal<ActionHandlerResolver> CURRENT = new ThreadLocal<>();
// 
//     public static ActionHandlerResolver getCurrent() {
//         return CURRENT.get();
//     }
// 
//     public static void setCurrent(ActionHandlerResolver resolver) {
//         CURRENT.set(resolver);
//     }
// 
//     private Set<ActionHandler> actionHandlers;
// 
//     private ActionHandlerResolver() {
//     }
// 
//     public void setActionHandlers(Set<ActionHandler> actionHandlers) {
//         this.actionHandlers = actionHandlers;
//     }
// 
//     public List<ActionHandler> findHandlersFor(String action) {
//         List<ActionHandler> list = new ArrayList<>();
// 
//         for (ActionHandler actionHandler : actionHandlers) {
//             Class<?> actionClass = getHandledActionType(actionHandler.getClass());
// 
//             if (actionClass.getSimpleName().equals(action)) {
//                 list.add(actionHandler);
//             }
//         }
// 
//         return list;
//     }
// 
//     public Class<?> getHandledActionType(Class<?> clazz) {
//         Type[] genericInterfaces = clazz.getGenericInterfaces();
// 
//         ParameterizedType type = findByRawType(genericInterfaces, CommandHandler.class);
//         if (type == null) {
//             type = findByRawType(genericInterfaces, EventHandler.class);
//         }
// 
//         return (Class<?>) type.getActualTypeArguments()[0];
//     }
// 
//     private ParameterizedType findByRawType(Type[] genericInterfaces, Class<?> expectedRawType) {
//         for (Type type : genericInterfaces) {
//             if (type instanceof ParameterizedType) {
//                 ParameterizedType parametrized = (ParameterizedType) type;
// 
//                 if (expectedRawType.equals(parametrized.getRawType())) {
//                     return parametrized;
//                 }
//             }
//         }
// 
//         return null;
//     }
// 
//     public List<String> getSupportedActions() {
//         List<String> actions = new ArrayList<>();
//         for (ActionHandler actionHandler : actionHandlers) {
//             Class<?> actionClass = getHandledActionType(actionHandler.getClass());
//             String action = actionClass.getSimpleName();
// 
//             actions.add(action);
//         }
// 
//         return actions;
//     }
// 
//     public static ActionHandlerResolver newInstance() {
//         ActionHandlerResolver resolver = new ActionHandlerResolver();
//         setCurrent(resolver);
// 
//         return resolver;
//     }
// 
//     public <T extends ActionHandler> void registerActionHandler(T actionHandler) {
//         if (actionHandlers == null) {
//             actionHandlers = new HashSet<>();
//         }
// 
//         actionHandlers.add(actionHandler);
//     }
// }


// Path: services-infrastructure-messaging/src/main/java/io/plumery/messaging/local/LocalEventPublisher.java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.reflect.TypeToken;
import io.plumery.core.ActionHandler;
import io.plumery.core.Event;
import io.plumery.core.infrastructure.EventPublisher;
import io.plumery.messaging.ActionHandlerResolver;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

package io.plumery.messaging.local;



public class LocalEventPublisher implements EventPublisher {
    private final ActionHandlerResolver resolverProvider;

    /**
     * Inject lazy LocalActionHandlerResolver provider in order to be able using EventPublisher in action handlers (directly or indirectly);
     * @param resolverProvider
     */
    public LocalEventPublisher(ActionHandlerResolver resolverProvider) {
        this.resolverProvider = resolverProvider;
    }

    @Override
    public <T extends Event> void publish(String streamName, T event) {
        List<ActionHandler> handlers = resolverProvider.findHandlersFor(event.getClass().getSimpleName());

        if(handlers != null && handlers.size() > 0) {
            for (ActionHandler<T> handler : handlers) {
                try {
                    ObjectMapper mapper = new ObjectMapper();
                    Method handleMethod = getHandlingMethod(handler);
                    Class expectedEventType