SpringCommandBus.java

package es.um.atica.shared.adapters.cqrs;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import es.um.atica.shared.domain.cqrs.Command;
import es.um.atica.shared.domain.cqrs.CommandBus;
import es.um.atica.shared.domain.cqrs.CommandHandler;
import es.um.atica.shared.domain.cqrs.SyncCommand;
import es.um.atica.shared.domain.cqrs.SyncCommandBus;
import es.um.atica.shared.domain.cqrs.SyncCommandHandler;

@Component
@Primary
public class SpringCommandBus implements CommandBus,SyncCommandBus {

    private Map<Class, CommandHandler> handlers;
    private Map<Class, SyncCommandHandler> syncHandlers;
    private ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();

    public SpringCommandBus(List<CommandHandler> commandHandlerImplementations, List<SyncCommandHandler> syncCommandHandlerImplementations) {
        this.handlers = new HashMap<>();
        commandHandlerImplementations.forEach(commandHandler -> {
            Class<?> commandClass = getCommandClass(commandHandler);
            handlers.put(commandClass, commandHandler);
        });
        this.syncHandlers = new HashMap<>();
        syncCommandHandlerImplementations.forEach(syncCommandHandler -> {
            Class<?> commandClass = getCommandClass(syncCommandHandler);
            syncHandlers.put(commandClass, syncCommandHandler);
        });
    }


    @Override
    public void handle(Command command) throws Exception {
        if (!handlers.containsKey(command.getClass())) {
            throw new Exception(String.format("No handler for %s", command.getClass().getName()));
        }
        executor.submit(()->{
            handlers.get(command.getClass()).handle(command);
        });
    }

    @Override
    public <T> T handle(SyncCommand<T> command) throws Exception {
        if (!syncHandlers.containsKey(command.getClass())) {
            throw new Exception(String.format("No handler for %s", command.getClass().getName()));
        }
        return (T) syncHandlers.get(command.getClass()).handle(command);
    }

    private Class<?> getCommandClass(CommandHandler handler) {
        Type commandInterface = ((ParameterizedType) handler.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
        return getClass(commandInterface.getTypeName());
    }

    private Class<?> getCommandClass(SyncCommandHandler synchandler) {
        Type commandInterface = ((ParameterizedType) synchandler.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[1];
        return getClass(commandInterface.getTypeName());
    }

    private Class<?> getClass(String name) {
        try {
            return Class.forName(name);
        } catch (Exception e) {
            return null;
        }
    }


}