com.hazelcast.simulator.protocol.connector.CoordinatorConnector.java Source code

Java tutorial

Introduction

Here is the source code for com.hazelcast.simulator.protocol.connector.CoordinatorConnector.java

Source

/*
 * Copyright (c) 2008-2015, Hazelcast, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hazelcast.simulator.protocol.connector;

import com.hazelcast.simulator.coordinator.FailureContainer;
import com.hazelcast.simulator.coordinator.PerformanceStateContainer;
import com.hazelcast.simulator.coordinator.TestHistogramContainer;
import com.hazelcast.simulator.coordinator.TestPhaseListenerContainer;
import com.hazelcast.simulator.protocol.core.Response;
import com.hazelcast.simulator.protocol.core.ResponseFuture;
import com.hazelcast.simulator.protocol.core.SimulatorAddress;
import com.hazelcast.simulator.protocol.core.SimulatorMessage;
import com.hazelcast.simulator.protocol.core.SimulatorProtocolException;
import com.hazelcast.simulator.protocol.exception.LocalExceptionLogger;
import com.hazelcast.simulator.protocol.handler.MessageConsumeHandler;
import com.hazelcast.simulator.protocol.handler.MessageEncoder;
import com.hazelcast.simulator.protocol.handler.ResponseEncoder;
import com.hazelcast.simulator.protocol.handler.ResponseHandler;
import com.hazelcast.simulator.protocol.handler.SimulatorFrameDecoder;
import com.hazelcast.simulator.protocol.handler.SimulatorProtocolDecoder;
import com.hazelcast.simulator.protocol.operation.SimulatorOperation;
import com.hazelcast.simulator.protocol.processors.CoordinatorOperationProcessor;
import com.hazelcast.simulator.utils.ThreadSpawner;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import static com.hazelcast.simulator.protocol.connector.ServerConnector.DEFAULT_SHUTDOWN_QUIET_PERIOD;
import static com.hazelcast.simulator.protocol.connector.ServerConnector.DEFAULT_SHUTDOWN_TIMEOUT;
import static com.hazelcast.simulator.protocol.core.ResponseType.FAILURE_AGENT_NOT_FOUND;
import static com.hazelcast.simulator.protocol.core.SimulatorAddress.COORDINATOR;
import static com.hazelcast.simulator.protocol.operation.OperationCodec.toJson;
import static com.hazelcast.simulator.protocol.operation.OperationType.getOperationType;
import static java.lang.String.format;
import static org.junit.Assert.fail;

/**
 * Connector which connects to remote Simulator Agent instances.
 */
public class CoordinatorConnector implements ClientPipelineConfigurator {

    private static final Logger LOGGER = Logger.getLogger(CoordinatorConnector.class);

    private final EventLoopGroup group = new NioEventLoopGroup();
    private final AtomicLong messageIds = new AtomicLong();
    private final ConcurrentMap<Integer, ClientConnector> agents = new ConcurrentHashMap<Integer, ClientConnector>();
    private final LocalExceptionLogger exceptionLogger = new LocalExceptionLogger();

    private final CoordinatorOperationProcessor processor;

    public CoordinatorConnector(TestPhaseListenerContainer testPhaseListenerContainer,
            PerformanceStateContainer performanceStateContainer, TestHistogramContainer testHistogramContainer,
            FailureContainer failureContainer) {
        this.processor = new CoordinatorOperationProcessor(exceptionLogger, testPhaseListenerContainer,
                performanceStateContainer, testHistogramContainer, failureContainer);
    }

    @Override
    public void configureClientPipeline(ChannelPipeline pipeline, SimulatorAddress remoteAddress,
            ConcurrentMap<String, ResponseFuture> futureMap) {
        pipeline.addLast("messageEncoder", new MessageEncoder(COORDINATOR, remoteAddress));
        pipeline.addLast("responseEncoder", new ResponseEncoder(COORDINATOR));
        pipeline.addLast("frameDecoder", new SimulatorFrameDecoder());
        pipeline.addLast("protocolDecoder", new SimulatorProtocolDecoder(COORDINATOR));
        pipeline.addLast("responseHandler", new ResponseHandler(COORDINATOR, remoteAddress, futureMap));
        pipeline.addLast("messageConsumeHandler", new MessageConsumeHandler(COORDINATOR, processor));
    }

    /**
     * Disconnects from all Simulator Agent instances.
     */
    public void shutdown() {
        ThreadSpawner spawner = new ThreadSpawner("shutdownClientConnectors", true);
        for (final ClientConnector agent : agents.values()) {
            spawner.spawn(new Runnable() {
                @Override
                public void run() {
                    agent.shutdown();
                }
            });
        }
        spawner.awaitCompletion();

        processor.shutdown();
        group.shutdownGracefully(DEFAULT_SHUTDOWN_QUIET_PERIOD, DEFAULT_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS)
                .syncUninterruptibly();
    }

    /**
     * Adds a Simulator Agent and connects to it.
     *
     * @param agentIndex the index of the Simulator Agent
     * @param agentHost  the host of the Simulator Agent
     * @param agentPort  the port of the Simulator Agent
     */
    public void addAgent(int agentIndex, String agentHost, int agentPort) {
        ConcurrentHashMap<String, ResponseFuture> futureMap = new ConcurrentHashMap<String, ResponseFuture>();
        ClientConnector client = new ClientConnector(this, group, futureMap, COORDINATOR,
                COORDINATOR.getChild(agentIndex), agentIndex, agentHost, agentPort);
        client.start();

        agents.put(agentIndex, client);
    }

    /**
     * Removes a Simulator Agent.
     *
     * @param agentIndex the index of the remote Simulator Agent
     */
    public void removeAgent(int agentIndex) {
        ClientConnector clientConnector = agents.remove(agentIndex);
        if (clientConnector != null) {
            clientConnector.shutdown();
        }
    }

    /**
     * Sends a {@link SimulatorMessage} to the addressed Simulator component.
     *
     * @param destination the {@link SimulatorAddress} of the destination
     * @param operation   the {@link SimulatorOperation} to send
     * @return a {@link Response} with the response of all addressed Simulator components.
     */
    public Response write(SimulatorAddress destination, SimulatorOperation operation) {
        SimulatorMessage message = new SimulatorMessage(destination, COORDINATOR, messageIds.incrementAndGet(),
                getOperationType(operation), toJson(operation));

        int agentAddressIndex = destination.getAgentIndex();
        Response response = new Response(message);
        if (agentAddressIndex == 0) {
            List<ResponseFuture> futureList = new ArrayList<ResponseFuture>();
            for (ClientConnector agent : agents.values()) {
                futureList.add(agent.writeAsync(message));
            }
            try {
                for (ResponseFuture future : futureList) {
                    response.addResponse(future.get());
                }
            } catch (InterruptedException e) {
                throw new SimulatorProtocolException("ResponseFuture.get() got interrupted!", e);
            }
        } else {
            ClientConnector agent = agents.get(agentAddressIndex);
            if (agent == null) {
                response.addResponse(COORDINATOR, FAILURE_AGENT_NOT_FOUND);
            } else {
                response.addResponse(agent.write(message));
            }
        }
        return response;
    }

    /**
     * Returns the number of collected exceptions.
     *
     * @return the number of exceptions.
     */
    public int getExceptionCount() {
        return exceptionLogger.getExceptionCount();
    }

    /**
     * Asserts that the {@link ResponseFuture} maps from all connected {@link ClientConnector} instances are empty.
     */
    public void assertEmptyFutureMaps() {
        for (ClientConnector clientConnector : agents.values()) {
            ConcurrentMap<String, ResponseFuture> futureMap = clientConnector.getFutureMap();
            SimulatorAddress remoteAddress = clientConnector.getRemoteAddress();
            int futureMapSize = futureMap.size();
            if (futureMapSize > 0) {
                LOGGER.error("Future entries: " + futureMap.toString());
                fail(format("FutureMap of ClientConnector %s is not empty", remoteAddress));
            }
        }
    }
}