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

dev.galasa.cps.etcd.internal.Etcd3ConfigurationPropertyStore Maven / Gradle / Ivy

The newest version!
/*
 * Copyright contributors to the Galasa project
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package dev.galasa.cps.etcd.internal;

import static com.google.common.base.Charsets.UTF_8;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;

import dev.galasa.framework.spi.ConfigurationPropertyStoreException;
import dev.galasa.framework.spi.IConfigurationPropertyStore;
import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.KV;
import io.etcd.jetcd.KeyValue;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.options.GetOption;
import io.etcd.jetcd.options.OptionsUtil;

/**
 * This class impletements the CPS for etcd using the JETCD client.
 * 
 * @author James Davies
 * @author Matthew Chivers
 */
public class Etcd3ConfigurationPropertyStore implements IConfigurationPropertyStore {
    private final Client client;
    private final KV kvClient;

    /**
     * This constructor create a priate KVClient from JETCD for store interactions.
     * 
     * @param cpsUri - location of the etcd
     */
    public Etcd3ConfigurationPropertyStore(URI cpsUri) {
        client = Client.builder().endpoints(cpsUri).build();
        kvClient = client.getKVClient();
    }

    /**
     * This is the only method for CPS as managers should only need to get
     * properties from the CPS and not set or watch any.
     * 
     * @param key The property to get
     */
    @Override
    public @Null String getProperty(@NotNull String key) throws ConfigurationPropertyStoreException {
        ByteSequence bsKey = ByteSequence.from(key, UTF_8);
        CompletableFuture getFuture = kvClient.get(bsKey);
        try {
            GetResponse response = getFuture.get();
            List kvs = response.getKvs();
            if (kvs.isEmpty()) {
                return null;
            }
            return kvs.get(0).getValue().toString(UTF_8);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not retrieve key, interrupted", e);
        } catch (ExecutionException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not retrieve key", e);
        }
    }

    @Override
    public @NotNull Map getPrefixedProperties(@NotNull String prefix)
            throws ConfigurationPropertyStoreException {
        
        HashMap returnValues = new HashMap<>();
        
        ByteSequence bsKey = ByteSequence.from(prefix, UTF_8);
        ByteSequence prefixEnd = OptionsUtil.prefixEndOf(bsKey);
        GetOption option = GetOption.builder().withRange(prefixEnd).build();
        CompletableFuture getFuture = kvClient.get(bsKey, option);  
        try {
            GetResponse response = getFuture.get();
            List kvs = response.getKvs();
            for(KeyValue kv : kvs) {
                returnValues.put(kv.getKey().toString(UTF_8), kv.getValue().toString(UTF_8));
            }

            return returnValues;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not retrieve key, interrupted", e);
        } catch (ExecutionException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not retrieve key", e);
        }
    }

    @Override
    public void shutdown() throws ConfigurationPropertyStoreException {
        kvClient.close();
        client.close();
    }

    @Override
    public void setProperty(@NotNull String key, @NotNull String value) throws ConfigurationPropertyStoreException {
        ByteSequence bytesKey = ByteSequence.from(key, UTF_8);
        ByteSequence bytesValue = ByteSequence.from(value, UTF_8);
        try {
            kvClient.put(bytesKey, bytesValue).get();
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not set key and value.", e);
        }
    }
    
    @Override
    public void deleteProperty(@NotNull String key) throws ConfigurationPropertyStoreException {
        ByteSequence bytesKey = ByteSequence.from(key, StandardCharsets.UTF_8);
        try {
            kvClient.delete(bytesKey).get();
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
            throw new ConfigurationPropertyStoreException("Could not delete key.", e);
        }
    }

    @Override
    public Map getPropertiesFromNamespace(String namespace) throws ConfigurationPropertyStoreException {
        ByteSequence bsNamespace = ByteSequence.from(namespace + ".", UTF_8);
        ByteSequence prefixEnd = OptionsUtil.prefixEndOf(ByteSequence.from(namespace + ".", UTF_8));
        GetOption option = GetOption.builder()
                .withSortField(GetOption.SortTarget.KEY)
                .withSortOrder(GetOption.SortOrder.DESCEND)
                .withRange(bsNamespace)
                .withRange(prefixEnd)
                .build();

        CompletableFuture futureResponse = client.getKVClient().get(bsNamespace, option);
        Map results = new HashMap<>();
        try {
            GetResponse response = futureResponse.get();
            List kvs = response.getKvs();
            for(KeyValue kv : kvs) {
                results.put(kv.getKey().toString(UTF_8), kv.getValue().toString(UTF_8));
            }
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
        }
        return results;
    }

    @Override
    public List getNamespaces() throws ConfigurationPropertyStoreException {
        ByteSequence empty = ByteSequence.from("\0", UTF_8);
        GetOption option = GetOption.builder()
                .withSortField(GetOption.SortTarget.KEY)
                .withSortOrder(GetOption.SortOrder.DESCEND)
                .withRange(empty)
                .build();

        CompletableFuture futureResponse = client.getKVClient().get(empty, option);
        List results = new ArrayList<>();
        try {
            GetResponse response = futureResponse.get();
            List kvs = response.getKvs();
            for(KeyValue kv : kvs) {
                String key = kv.getKey().toString(UTF_8);
                // Ignore any etcd keys which don't have a '.' character.
                int indexOfFirstDot = key.indexOf(".");
                if (indexOfFirstDot >= 0) {
                    String namespace = key.substring(0,indexOfFirstDot);
                    if(!results.contains(namespace)) {
                        results.add(namespace);
                    }
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            Thread.currentThread().interrupt();
        }
        return results;
    }



}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy