com.ottogroup.bi.spqr.resman.node.SPQRNodeManager.java Source code

Java tutorial

Introduction

Here is the source code for com.ottogroup.bi.spqr.resman.node.SPQRNodeManager.java

Source

/**
 * Copyright 2015 Otto (GmbH & Co KG)
 *
 * 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.ottogroup.bi.spqr.resman.node;

import io.dropwizard.client.JerseyClientBuilder;

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

import javax.ws.rs.client.Client;

import org.apache.commons.lang3.StringUtils;

import com.fasterxml.uuid.EthernetAddress;
import com.fasterxml.uuid.Generators;
import com.fasterxml.uuid.impl.TimeBasedGenerator;
import com.ottogroup.bi.spqr.exception.RequiredInputMissingException;
import com.ottogroup.bi.spqr.node.message.NodeDeRegistration.NodeDeRegistrationResponse;
import com.ottogroup.bi.spqr.node.message.NodeDeRegistration.NodeDeRegistrationState;
import com.ottogroup.bi.spqr.node.message.NodeRegistration.NodeRegistrationResponse;
import com.ottogroup.bi.spqr.node.message.NodeRegistration.NodeRegistrationState;

/**
 * Keeps track of all processing nodes which registered themselves with the SQPR cluster. It provides direct
 * access to each node through dedicated {@link SPQRNodeClient} instances. Aside it manages a set of 
 * {@link SPQRNodeSupervisor supervisors} which look after a single node, retrieve statistical data and 
 * ensures that managed nodes are still alive.  
 * @author mnxfst
 * @since Apr 14, 2015
 */
public class SPQRNodeManager {

    /** UUID generator based on ethernet address of the server this application is executed on */
    private final TimeBasedGenerator uuidGenerator = Generators.timeBasedGenerator(EthernetAddress.fromInterface());
    /** keeps track of all registered spqr nodes */
    private final Map<String, SPQRNodeClient> processingNodes = new HashMap<>();
    /** number of retries to compute an unique node identifier */
    private final int numIdentifierComputationRetries;
    /** builder to use for creating new rest client */
    private final JerseyClientBuilder httpClientBuilder;

    /**
     * Initializes the manager using the provided input
     * @param numIdentifierComputationRetries
     * @param httpClientBuilder
     */
    public SPQRNodeManager(final int numIdentifierComputationRetries, final JerseyClientBuilder httpClientBuilder) {
        this.numIdentifierComputationRetries = numIdentifierComputationRetries;
        this.httpClientBuilder = httpClientBuilder;
    }

    /**
     * Registers a new processing node living at the given host and reachable at the provided ports (admin and service).  
     * @param remoteHost
     * @param servicePort
     * @param adminPort
     * @return
     */
    public NodeRegistrationResponse registerNode(final String protocol, final String remoteHost,
            final int servicePort, final int adminPort) {

        if (StringUtils.isBlank(protocol))
            return new NodeRegistrationResponse("", NodeRegistrationState.MISSING_PROTOCOL,
                    "Missing required protocol");
        if (StringUtils.isBlank(remoteHost))
            return new NodeRegistrationResponse("", NodeRegistrationState.MISSING_HOST,
                    "Missing required remote host");
        if (servicePort < 1)
            return new NodeRegistrationResponse("", NodeRegistrationState.MISSING_SERVICE_PORT,
                    "Missing required service port");
        if (adminPort < 1)
            return new NodeRegistrationResponse("", NodeRegistrationState.MISSING_ADMIN_PORT,
                    "Missing required admin port");

        ///////////////////////////////////////////////////////////////////////////////
        // compute identifier assigned to node
        String nodeId = null;
        int retries = this.numIdentifierComputationRetries;
        while (retries > 0) {
            nodeId = uuidGenerator.generate().toString();
            if (!this.processingNodes.containsKey(nodeId))
                break;
        }
        if (nodeId == null || this.processingNodes.containsKey(nodeId))
            return new NodeRegistrationResponse("", NodeRegistrationState.NODE_ID_COMPUTATION_FAILED,
                    "Failed to compute node identifier");
        //
        ///////////////////////////////////////////////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////////
        // register client to access remote node if required
        try {
            this.processingNodes.put(nodeId,
                    new SPQRNodeClient(protocol, remoteHost, servicePort, adminPort, getHttpClient(nodeId)));
        } catch (RequiredInputMissingException e) {
            return new NodeRegistrationResponse("", NodeRegistrationState.TECHNICAL_ERROR,
                    "Failed to create spqr node client. Error: " + e.getMessage());
        }
        //
        ///////////////////////////////////////////////////////////////////////////////
        return new NodeRegistrationResponse(nodeId, NodeRegistrationState.OK, "");
    }

    /**
     * De-registers the referenced node 
     * @param nodeId
     * @return
     */
    public NodeDeRegistrationResponse deregisterNode(final String nodeId) {

        /////////////////////////////////////////////////////////////////////////////
        // validate input
        if (StringUtils.isBlank(nodeId))
            return new NodeDeRegistrationResponse("", NodeDeRegistrationState.MISSING_NODE_ID, "");
        String id = StringUtils.lowerCase(StringUtils.trim(nodeId));
        if (!this.processingNodes.containsKey(id))
            return new NodeDeRegistrationResponse(nodeId, NodeDeRegistrationState.NO_SUCH_NODE_ID,
                    "Unknown node id: " + nodeId);
        //
        /////////////////////////////////////////////////////////////////////////////

        final SPQRNodeClient client = this.processingNodes.remove(id);
        if (client != null)
            client.shutdown();

        return new NodeDeRegistrationResponse(nodeId, NodeDeRegistrationState.OK, "");
    }

    /**
     * Returns true in case the reference node is registered with this manager instance
     * @param nodeId
     * @return
     */
    public boolean hasNode(final String nodeId) {
        return this.processingNodes.containsKey(StringUtils.lowerCase(StringUtils.trim(nodeId)));
    }

    /**
     * Creates a new {@link Client} instance and assigns the given identifier
     * @param clientId
     * @return
     */
    protected Client getHttpClient(final String clientId) {
        return httpClientBuilder.build(clientId);
    }

}