org.sfs.nodes.RemoteMasterNode.java Source code

Java tutorial

Introduction

Here is the source code for org.sfs.nodes.RemoteMasterNode.java

Source

/*
 * Copyright 2016 The Simple File Server Authors
 *
 * 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 org.sfs.nodes;

import com.google.common.net.HostAndPort;
import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.apache.http.HttpHeaders;
import org.sfs.Server;
import org.sfs.VertxContext;
import org.sfs.jobs.Jobs;
import org.sfs.rx.BufferToJsonObject;
import org.sfs.rx.Defer;
import org.sfs.rx.HttpClientKeepAliveResponseBodyBuffer;
import org.sfs.rx.ObservableFuture;
import org.sfs.rx.RxHelper;
import org.sfs.rx.ToVoid;
import org.sfs.util.HttpBodyLogger;
import org.sfs.util.HttpClientRequestAndResponse;
import org.sfs.util.HttpClientResponseHeaderLogger;
import rx.Observable;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

import static com.google.common.io.BaseEncoding.base64;
import static java.net.HttpURLConnection.HTTP_CONFLICT;
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.sfs.jobs.Jobs.Parameters.JOB_ID;
import static org.sfs.util.SfsHttpHeaders.X_SFS_REMOTE_NODE_TOKEN;

public class RemoteMasterNode implements MasterNode {

    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteMasterNode.class);
    private final Vertx vertx;
    private final Collection<HostAndPort> hostAndPorts;
    private final int responseTimeout;
    private final String remoteNodeSecret;
    private final HttpClient httpClient;
    private final Nodes nodes;

    public RemoteMasterNode(VertxContext<Server> vertxContext, int responseTimeout,
            Collection<HostAndPort> hostAndPorts) {
        this.responseTimeout = responseTimeout;
        this.hostAndPorts = hostAndPorts;
        this.remoteNodeSecret = base64().encode(vertxContext.verticle().getRemoteNodeSecret());
        this.httpClient = vertxContext.verticle().httpClient(false);
        this.vertx = vertxContext.vertx();
        this.nodes = vertxContext.verticle().nodes();
    }

    @Override
    public Observable<Void> executeJob(String jobId, MultiMap params, long timeout, TimeUnit timeUnit) {
        return Defer.aVoid().flatMap(aVoid -> nodes.connectFirstAvailable(vertx, hostAndPorts, hostAndPort -> {
            ObservableFuture<HttpClientResponse> handler = RxHelper.observableFuture();

            String url = String.format("http://%s/_internal_node_master_execute_job/", hostAndPort.toString());

            HttpClientRequest httpClientRequest = httpClient.postAbs(url, httpClientResponse -> {
                httpClientResponse.pause();
                handler.complete(httpClientResponse);
            }).exceptionHandler(handler::fail).putHeader(X_SFS_REMOTE_NODE_TOKEN, remoteNodeSecret)
                    .putHeader(JOB_ID, jobId)
                    .putHeader(HttpHeaders.TIMEOUT, String.valueOf(timeUnit.toMillis(timeout)))
                    .setTimeout(responseTimeout);
            httpClientRequest.headers().addAll(params);

            httpClientRequest.end();

            return handler.map(
                    httpClientResponse -> new HttpClientRequestAndResponse(httpClientRequest, httpClientResponse));
        })).map(HttpClientRequestAndResponse::getResponse).map(new HttpClientResponseHeaderLogger())
                .flatMap(httpClientResponse -> Defer.just(httpClientResponse)
                        .flatMap(new HttpClientKeepAliveResponseBodyBuffer()).map(new HttpBodyLogger())
                        .map(buffer -> {
                            if (HTTP_OK != httpClientResponse.statusCode()) {
                                throw new HttpClientResponseException(httpClientResponse, buffer);
                            }
                            return buffer;
                        }).map(new BufferToJsonObject()).map(jsonObject -> {
                            Integer code = jsonObject.getInteger("code");
                            if (code != null) {
                                if (HTTP_OK == code) {
                                    return jsonObject;
                                } else if (HTTP_CONFLICT == code) {
                                    return new Jobs.JobAlreadyRunning();
                                } else if (HTTP_NOT_FOUND == code) {
                                    throw new Jobs.JobNotFound();
                                }
                            }
                            throw new HttpClientResponseException(httpClientResponse, jsonObject);
                        }))
                .map(new ToVoid<>());
    }

    @Override
    public Observable<Void> waitForJob(String jobId, long timeout, TimeUnit timeUnit) {
        return Defer.aVoid().flatMap(aVoid -> nodes.connectFirstAvailable(vertx, hostAndPorts, hostAndPort -> {
            ObservableFuture<HttpClientResponse> handler = RxHelper.observableFuture();

            String url = String.format("http://%s/_internal_node_master_wait_for_job/", hostAndPort.toString());

            HttpClientRequest httpClientRequest = httpClient.postAbs(url, httpClientResponse -> {
                httpClientResponse.pause();
                handler.complete(httpClientResponse);
            }).exceptionHandler(handler::fail).putHeader(X_SFS_REMOTE_NODE_TOKEN, remoteNodeSecret)
                    .putHeader(JOB_ID, jobId)
                    .putHeader(HttpHeaders.TIMEOUT, String.valueOf(timeUnit.toMillis(timeout)))
                    .setTimeout(responseTimeout);

            httpClientRequest.end();

            return handler.map(
                    httpClientResponse -> new HttpClientRequestAndResponse(httpClientRequest, httpClientResponse));
        })).map(HttpClientRequestAndResponse::getResponse).map(new HttpClientResponseHeaderLogger())
                .flatMap(httpClientResponse -> Defer.just(httpClientResponse)
                        .flatMap(new HttpClientKeepAliveResponseBodyBuffer()).map(new HttpBodyLogger())
                        .map(buffer -> {
                            if (HTTP_OK != httpClientResponse.statusCode()) {
                                throw new HttpClientResponseException(httpClientResponse, buffer);
                            }
                            return buffer;
                        }).map(new BufferToJsonObject()).map(jsonObject -> {
                            Integer code = jsonObject.getInteger("code");
                            if (code != null) {
                                if (HTTP_OK == code) {
                                    return jsonObject;
                                } else if (HTTP_CONFLICT == code) {
                                    return new Jobs.WaitStoppedExpired();
                                } else if (HTTP_NOT_FOUND == code) {
                                    throw new Jobs.JobNotFound();
                                }
                            }
                            throw new HttpClientResponseException(httpClientResponse, jsonObject);
                        }))
                .map(new ToVoid<>());
    }

    @Override
    public Observable<Void> stopJob(String jobId, long timeout, TimeUnit timeUnit) {
        return Defer.aVoid().flatMap(aVoid -> nodes.connectFirstAvailable(vertx, hostAndPorts, hostAndPort -> {
            ObservableFuture<HttpClientResponse> handler = RxHelper.observableFuture();

            String url = String.format("http://%s/_internal_node_master_stop_job/", hostAndPort.toString());

            HttpClientRequest httpClientRequest = httpClient.postAbs(url, httpClientResponse -> {
                httpClientResponse.pause();
                handler.complete(httpClientResponse);
            }).exceptionHandler(handler::fail).putHeader(X_SFS_REMOTE_NODE_TOKEN, remoteNodeSecret)
                    .putHeader(JOB_ID, jobId)
                    .putHeader(HttpHeaders.TIMEOUT, String.valueOf(timeUnit.toMillis(timeout)))
                    .setTimeout(responseTimeout);

            httpClientRequest.end();

            return handler.map(
                    httpClientResponse -> new HttpClientRequestAndResponse(httpClientRequest, httpClientResponse));
        })).map(HttpClientRequestAndResponse::getResponse).map(new HttpClientResponseHeaderLogger())
                .flatMap(httpClientResponse -> Defer.just(httpClientResponse)
                        .flatMap(new HttpClientKeepAliveResponseBodyBuffer()).map(new HttpBodyLogger())
                        .map(buffer -> {
                            if (HTTP_OK != httpClientResponse.statusCode()) {
                                throw new HttpClientResponseException(httpClientResponse, buffer);
                            }
                            return buffer;
                        }).map(new BufferToJsonObject()).map(jsonObject -> {
                            Integer code = jsonObject.getInteger("code");
                            if (code != null) {
                                if (HTTP_OK == code) {
                                    return jsonObject;
                                } else if (HTTP_CONFLICT == code) {
                                    return new Jobs.WaitStoppedExpired();
                                } else if (HTTP_NOT_FOUND == code) {
                                    throw new Jobs.JobNotFound();
                                }
                            }
                            throw new HttpClientResponseException(httpClientResponse, jsonObject);
                        }))
                .map(new ToVoid<>());
    }

}