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

io.etcd.jetcd.Util Maven / Gradle / Ivy

There is a newer version: 0.8.4
Show newest version
/*
 * Copyright 2016-2021 The jetcd 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 io.etcd.jetcd;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.ByteString;
import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.stub.AbstractStub;
import io.grpc.stub.MetadataUtils;

import static io.etcd.jetcd.common.exception.EtcdExceptionFactory.toEtcdException;

public final class Util {

    private Util() {
    }

    public static List toURIs(Collection uris) {
        return uris.stream().map(uri -> {
            try {
                return new URI(uri);
            } catch (URISyntaxException e) {
                throw new IllegalArgumentException("Invalid endpoint URI: " + uri, e);
            }
        }).collect(Collectors.toList());
    }

    /**
     * convert ListenableFuture of Type S to CompletableFuture of Type T.
     */
    static  CompletableFuture toCompletableFuture(ListenableFuture sourceFuture, Function resultConvert,
        Executor executor) {

        CompletableFuture targetFuture = new CompletableFuture() {
            // the cancel of targetFuture also cancels the sourceFuture.
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                super.cancel(mayInterruptIfRunning);
                return sourceFuture.cancel(mayInterruptIfRunning);
            }
        };

        sourceFuture.addListener(() -> {
            try {
                targetFuture.complete(resultConvert.apply(sourceFuture.get()));
            } catch (Exception e) {
                targetFuture.completeExceptionally(toEtcdException(e));
            }
        }, executor);

        return targetFuture;
    }

    static boolean isRetryable(Throwable e) {
        Status status = Status.fromThrowable(e);
        return Status.UNAVAILABLE.getCode().equals(status.getCode()) || isInvalidTokenError(status);
    }

    static boolean isInvalidTokenError(Status status) {
        return status.getCode() == Status.Code.UNAUTHENTICATED
            && "etcdserver: invalid auth token".equals(status.getDescription());
    }

    static  T supplyIfNull(T target, Supplier supplier) {
        return target != null ? target : supplier.get();
    }

    public static ByteString prefixNamespace(ByteString key, ByteSequence namespace) {
        return namespace.isEmpty() ? key : namespace.getByteString().concat(key);
    }

    public static ByteString prefixNamespaceToRangeEnd(ByteString end, ByteSequence namespace) {
        if (namespace.isEmpty()) {
            return end;
        }

        if (end.size() == 1 && end.toByteArray()[0] == 0) {
            // range end is '\0', calculate the prefixed range end by (key + 1)
            byte[] prefixedEndArray = namespace.getByteString().toByteArray();
            boolean ok = false;
            for (int i = (prefixedEndArray.length - 1); i >= 0; i--) {
                prefixedEndArray[i] = (byte) (prefixedEndArray[i] + 1);
                if (prefixedEndArray[i] != 0) {
                    ok = true;
                    break;
                }
            }
            if (!ok) {
                // 0xff..ff => 0x00
                prefixedEndArray = new byte[] { 0 };
            }
            return ByteString.copyFrom(prefixedEndArray);
        } else {
            return namespace.getByteString().concat(end);
        }
    }

    public static ByteString unprefixNamespace(ByteString key, ByteSequence namespace) {
        return namespace.isEmpty() ? key : key.substring(namespace.size());
    }

    static > T applyRequireLeader(boolean requireLeader, T stub) {
        if (!requireLeader) {
            return stub;
        }
        final Metadata md = new Metadata();
        md.put(Constants.REQUIRE_LEADER_KEY, Constants.REQUIRE_LEADER_VALUE);
        return MetadataUtils.attachHeaders(stub, md);
    }

    public static boolean isHaltError(final Status status) {
        return status.getCode() != Status.Code.UNAVAILABLE && status.getCode() != Status.Code.INTERNAL;
    }

    static final String NO_LEADER_ERROR_MESSAGE = "etcdserver: no leader";

    public static boolean isNoLeaderError(final Status status) {
        return status.getCode() == Status.Code.UNAVAILABLE && NO_LEADER_ERROR_MESSAGE.equals(status.getDescription());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy