All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opencredo.concursus.hazelcast.commands.HazelcastCommandExecutorConfiguration Maven / Gradle / Ivy

The newest version!
package com.opencredo.concursus.hazelcast.commands;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hazelcast.config.Config;
import com.hazelcast.config.ExecutorConfig;
import com.hazelcast.config.SerializerConfig;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.ManagedContext;
import com.opencredo.concursus.domain.commands.CommandType;
import com.opencredo.concursus.domain.commands.CommandTypeInfo;
import com.opencredo.concursus.domain.commands.CommandTypeMatcher;
import com.opencredo.concursus.domain.commands.dispatching.CommandExecutor;
import com.opencredo.concursus.mapping.commands.methods.dispatching.CommandHandlerSubscribable;
import com.opencredo.concursus.mapping.commands.methods.dispatching.MethodDispatchingCommandProcessor;
import com.opencredo.concursus.mapping.commands.methods.reflection.CommandInterfaceInfo;

import java.util.HashMap;
import java.util.Map;

/**
 * Used to configure a {@link HazelcastInstance} with a suitable {@link com.hazelcast.core.IExecutorService} for
 * distributed execution of commands, and a custom {@link com.hazelcast.nio.serialization.Serializer} that can
 * serialise and deserialise command requests for execution on remote nodes, to support the use of the
 * {@link HazelcastCommandExecutor}.
 */
public final class HazelcastCommandExecutorConfiguration implements CommandHandlerSubscribable {

    /**
     * Create a {@link HazelcastCommandExecutorConfiguration} using the supplied {@link ObjectMapper} for JSON
     * serialisation, with a default executor name "concursus" and default one-thread-per-node configuration.
     * @param objectMapper the {@link ObjectMapper} to use for JSON serialisation.
     * @return The constructed {@link HazelcastCommandExecutorConfiguration}.
     */
    public static HazelcastCommandExecutorConfiguration using(ObjectMapper objectMapper) {
        return using(objectMapper, "concursus", 1);
    }

    /**
     * Create a {@link HazelcastCommandExecutorConfiguration} using the supplied {@link ObjectMapper} for JSON
     * serialisation, with the supplied executor name and threads-per-node configuration.
     * @param objectMapper the {@link ObjectMapper} to use for JSON serialisation.
     * @param executorName The name to use for the {@link com.hazelcast.core.IExecutorService}.
     * @param threadsPerNode The number of threads each node provides to the {@link com.hazelcast.core.IExecutorService}.
     * @return The constructed {@link HazelcastCommandExecutorConfiguration}.
     */
    public static HazelcastCommandExecutorConfiguration using(ObjectMapper objectMapper, String executorName, int threadsPerNode) {
        return new HazelcastCommandExecutorConfiguration(objectMapper, executorName, threadsPerNode);
    }

    private final ObjectMapper objectMapper;
    private final String executorName;
    private final int threadsPerNode;
    private final Map typeInfoMap = new HashMap<>();
    private final MethodDispatchingCommandProcessor dispatchingCommandProcessor =
            MethodDispatchingCommandProcessor.create();

    private HazelcastCommandExecutorConfiguration(ObjectMapper objectMapper, String executorName, int threadsPerNode) {
        this.objectMapper = objectMapper;
        this.executorName = executorName;
        this.threadsPerNode = threadsPerNode;
    }

    /**
     * Add configuration to the supplied {@link Config} to support the use of a {@link HazelcastCommandExecutor}.
     * @param config The {@link Config} to configure.
     * @return The updated {@link Config}.
     */
    public Config addCommandExecutorConfiguration(Config config) {
        SerializerConfig serializerConfig = new SerializerConfig()
                .setImplementation(RemoteCommandSerialiser.using(
                        objectMapper,
                        CommandTypeMatcher.matchingAgainst(typeInfoMap)))
                .setTypeClass(RemoteCommand.class);

        ManagedContext managedContext = CommandProcessingManagedContext
                .processingCommandsWith(dispatchingCommandProcessor);

        config.getSerializationConfig().addSerializerConfig(serializerConfig);

        config.setManagedContext(config.getManagedContext() == null
                ? managedContext
                : CompositeManagedContext.of(managedContext, config.getManagedContext()));

        config.addExecutorConfig(new ExecutorConfig(executorName, threadsPerNode));
        return config;
    }

    /**
     * Create a {@link CommandExecutor} which dispatches commands to Hazelcast nodes for execution.
     * @param hazelcastInstance The {@link HazelcastInstance} to obtain
     * @return
     */
    public CommandExecutor getCommandExecutor(HazelcastInstance hazelcastInstance) {
        return HazelcastCommandExecutor.using(hazelcastInstance.getExecutorService(executorName));
    }

    @Override
    public  CommandHandlerSubscribable subscribe(Class handlerClass, H commandHandler) {
        typeInfoMap.putAll(CommandInterfaceInfo.forInterface(handlerClass).getTypeInfoMap());
        dispatchingCommandProcessor.subscribe(handlerClass, commandHandler);
        return this;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy