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

com.datastax.astra.sdk.AstraClient Maven / Gradle / Ivy

There is a newer version: 1.2.9
Show newest version
/*
 * Copyright DataStax, Inc.
 *
 * 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.datastax.astra.sdk;

import com.datastax.astra.sdk.config.AstraClientConfig;
import com.datastax.oss.driver.api.core.CqlSession;
import com.dtsx.astra.sdk.AstraDevopsApiClient;
import com.dtsx.astra.sdk.db.exception.DatabaseNotFoundException;
import com.dtsx.astra.sdk.utils.ApiLocator;
import io.stargate.sdk.StargateClient;
import io.stargate.sdk.api.SimpleTokenProvider;
import io.stargate.sdk.doc.StargateDocumentApiClient;
import io.stargate.sdk.gql.StargateGraphQLApiClient;
import io.stargate.sdk.grpc.ServiceGrpc;
import io.stargate.sdk.grpc.StargateGrpcApiClient;
import io.stargate.sdk.http.ServiceHttp;
import io.stargate.sdk.rest.StargateRestApiClient;
import io.stargate.sdk.utils.AnsiUtils;
import io.stargate.sdk.utils.Utils;
import com.dtsx.astra.sdk.db.AstraDbClient;
import com.dtsx.astra.sdk.db.domain.Database;
import com.dtsx.astra.sdk.streaming.AstraStreamingClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.File;
import java.util.Optional;

/**
 * Public interface to interact with ASTRA APIs.
 * 
 * @author Cedrick LUNVEN (@clunven)
 */
public class AstraClient implements Closeable {
    
    /** Logger for our Client. */
    private static final Logger LOGGER = LoggerFactory.getLogger(AstraClient.class);
    
    /** Cloud Secure bundle file prefix, scb_dbId_dbRegion.zip */
    public static final String SECURE_CONNECT = "scb_";
    
    // -----------------------------------------------------
    // --------- Devops API Endpoints  ---------------------
    // -----------------------------------------------------

    /** Hold a reference for the Api Devops. */
    private AstraDevopsApiClient apiDevops;

    /** Hold a reference for the Api Devops. */
    private AstraDbClient apiDevopsDatabases;

    /** Hold a reference for the Api Devops. */
    private AstraStreamingClient apiDevopsStreaming;

    // -----------------------------------------------------
    // --------- Stargate APIs Settings --------------------
    // -----------------------------------------------------
    
    /** Access to all Stargate sub Api (rest, graphQL, doc, gRPC). */
    protected StargateClient stargateClient;
    
    /** Keep some information related to Astra Settings. */
    protected AstraClientConfig astraClientConfig;
   
    /** Hold a reference on current region used for the Fail-over. */
    protected String currentDatabaseRegion;
    
    /**
     * Create a client with the token on
     *
     * @param token
     *      current token
     */
    public AstraClient(String token) {
        this(builder().withToken(token));
    }
    
    /**
     * Simple initialization.
     *
     * @param dbId
     *      database id
     * @param dbRegion
     *      database region
     * @param token
     *      current token
     */
    public AstraClient(String dbId, String dbRegion, String token) {
        this(builder()
                .withToken(token)
                .withDatabaseId(dbId)
                .withDatabaseRegion(dbRegion));
    }
    
    /**
     * Initialization through builder.
     * 
     * @param config
     *      configuration extracted from builder
     */
    public AstraClient(AstraClientConfig config) {
        this.astraClientConfig = config;
        
        // ---------------------------------------------------
        //  Devops APIS
        // ---------------------------------------------------
        if (Utils.hasLength(config.getToken())) {
            apiDevops           = new AstraDevopsApiClient(config.getToken());
            apiDevopsDatabases  = apiDevops.db();
            apiDevopsStreaming  = apiDevops.streaming();
            LOGGER.info("+ API(s) Devops     [" + AnsiUtils.green("ENABLED")+ "]");
        } else {
            LOGGER.info("+ API(s) Devops     [" + AnsiUtils.red("DISABLED")+ "]");
        }
       
        // ---------------------------------------------------
        //  Stargate 
        // ---------------------------------------------------
        
        if (Utils.hasAllLength(config.getDatabaseId(), config.getDatabaseRegion())) {
            LOGGER.info("+ Db: id [" 
                        + AnsiUtils.cyan("{}")+ "] and region ["
                        + AnsiUtils.cyan("{}")+ "]", 
                    config.getDatabaseId(), 
                    config.getDatabaseRegion());
            
            this.currentDatabaseRegion = config.getDatabaseRegion();
            
            // Set default region (not in the cql as SCB is there)
            config.getStargateConfig().setLocalDatacenter(config.getDatabaseRegion());
            
            // CqlSession should be initialized only if the flag is on.
            if (config.getStargateConfig().isEnabledCql()) {
            
                // Downloading SCB is enabled (default is true)
                if (config.isEnabledDownloadSecureConnectBundle()) {
                    downloadAndSetupSecureConnectBundle(config);
                }
                
                // ---------------------------------------------------
                //       CQL / Credentials
                // ---------------------------------------------------
                
                if (Utils.hasAllLength(config.getClientId(), config.getClientSecret())) {
                    config.getStargateConfig().withAuthCredentials(config.getClientId(), config.getClientSecret());
                } else {
                    config.getStargateConfig().withAuthCredentials("token", config.getToken());
                }
            }
            
            // ---------------------------------------------------
            //     Stargate Node per region
            // ---------------------------------------------------
            
            if (config.isEnabledCrossRegionFailOver()) {
                Database db = apiDevopsDatabases.database(config.getDatabaseId()).get();

                // Loop on regions. for each region a DC.
                db.getInfo().getDatacenters().forEach(dc -> {
                    // Rest Api
                    config.getStargateConfig().addServiceRest(dc.getRegion(),
                            new ServiceHttp(dc.getRegion() + "-rest",
                            ApiLocator.getApiRestEndpoint(config.getDatabaseId(), dc.getRegion()),
                            ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), dc.getRegion())));
                    // Document API
                    config.getStargateConfig().addDocumentService(dc.getRegion(),
                            new ServiceHttp(dc.getRegion() + "-doc",
                                    ApiLocator.getApiDocumentEndpoint(config.getDatabaseId(), dc.getRegion()),
                                    ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), dc.getRegion())));
                    // GraphQL
                    config.getStargateConfig().addGraphQLService(dc.getRegion(),
                            new ServiceHttp(dc.getRegion() + "-gql",
                                    ApiLocator.getApiGraphQLEndPoint(config.getDatabaseId(), dc.getRegion()),
                                    ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), dc.getRegion())));

                    if (config.getStargateConfig().isEnabledGrpc()) {
                        // Grpc
                        config.getStargateConfig().addGrpcService(dc.getRegion(), new ServiceGrpc(dc.getRegion() + "-grpc",
                                ApiLocator.getApiGrpcEndPoint(config.getDatabaseId(), dc.getRegion()) + ":" + AstraClientConfig.GRPC_PORT,
                                ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), dc.getRegion()), true));
                    }

                    if (config.getStargateConfig().isEnabledCql()) {
                        // Cloud Secure Bundle
                        config.getStargateConfig().withCqlCloudSecureConnectBundleDC(dc.getRegion(),
                                config.getSecureConnectBundleFolder()
                                        + File.separator
                                        + AstraClientConfig.buildScbFileName(config.getDatabaseId(), dc.getRegion()));
                    }

                    config.getStargateConfig().withApiTokenProviderDC(dc.getRegion(),
                            new SimpleTokenProvider(config.getToken()));

                });
                
            } else {

                LOGGER.info("+ Cross-region fallback is disabled.");
                // Authentication for the DB
                config.getStargateConfig().withApiTokenProviderDC(currentDatabaseRegion,
                        new SimpleTokenProvider(config.getToken()));
                // Rest Api
                config.getStargateConfig().addServiceRest(currentDatabaseRegion,
                        new ServiceHttp(currentDatabaseRegion+ "-rest",
                                ApiLocator.getApiRestEndpoint(config.getDatabaseId(), currentDatabaseRegion),
                                ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), currentDatabaseRegion)));
                // Document API
                config.getStargateConfig().addDocumentService(currentDatabaseRegion,
                        new ServiceHttp(currentDatabaseRegion + "-doc",
                                ApiLocator.getApiDocumentEndpoint(config.getDatabaseId(), currentDatabaseRegion),
                                ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), currentDatabaseRegion)));
                // GraphQL
                config.getStargateConfig().addGraphQLService(currentDatabaseRegion,
                        new ServiceHttp(currentDatabaseRegion + "-gql",
                                ApiLocator.getApiGraphQLEndPoint(config.getDatabaseId(), currentDatabaseRegion),
                                ApiLocator.getEndpointHealthCheck(config.getDatabaseId(),currentDatabaseRegion)));
                // Grpc
                if (config.getStargateConfig().isEnabledGrpc()) {
                    config.getStargateConfig().addGrpcService(currentDatabaseRegion, new ServiceGrpc(currentDatabaseRegion + "-grpc",
                            ApiLocator.getApiGrpcEndPoint(config.getDatabaseId(), currentDatabaseRegion) + ":" + AstraClientConfig.GRPC_PORT,
                            ApiLocator.getEndpointHealthCheck(config.getDatabaseId(), currentDatabaseRegion), true));
                }

                // CQL
                if (config.getStargateConfig().isEnabledCql()) {
                    config.getStargateConfig()
                            .withCqlCloudSecureConnectBundleDC(currentDatabaseRegion,
                                    config.getSecureConnectBundleFolder()
                                            + File.separator
                                            + AstraClientConfig.buildScbFileName(config.getDatabaseId(), currentDatabaseRegion));
                }
            }
            this.stargateClient = config.getStargateConfig().build();

        } else {
           LOGGER.info("+ API(s) CqlSession [" + AnsiUtils.red("DISABLED")+ "]");
           LOGGER.info("+ API(s) Document   [" + AnsiUtils.red("DISABLED")+ "]");
           LOGGER.info("+ API(s) Rest       [" + AnsiUtils.red("DISABLED")+ "]");
           LOGGER.info("+ API(s) gRPC       [" + AnsiUtils.red("DISABLED")+ "]");
        }
        LOGGER.info("[" + AnsiUtils.yellow("AstraClient") + "] has been initialized.");
    }
    
    /**
     * Download the secure connect bundle files.
     *
     * @param config
     *      configuration for client
     */
    private void downloadAndSetupSecureConnectBundle(AstraClientConfig config) {
        if (!new File(config.getSecureConnectBundleFolder()).exists()) {
            if (new File(config.getSecureConnectBundleFolder()).mkdirs()) {
                LOGGER.info("+ Folder Created to hold SCB");
            }
        }
        // Download secure bundles (if needed)
        LOGGER.info("+ Downloading bundles in: [" + AnsiUtils.cyan("{}") + "]", config.getSecureConnectBundleFolder());
        apiDevopsDatabases.database(config.getDatabaseId())
                          .downloadAllSecureConnectBundles(config.getSecureConnectBundleFolder());
        
        // Set up the current region
        String scbFile = config.getSecureConnectBundleFolder() 
                + File.separator 
                + AstraClientConfig.buildScbFileName(config.getDatabaseId(), config.getDatabaseRegion());
        config.getStargateConfig().withCqlCloudSecureConnectBundle(scbFile);
    }
    
    /**
     * Document Api.
     * 
     * @return ApiDocumentClient
     */
    public StargateDocumentApiClient apiStargateDocument() {
        if (stargateClient == null) {
            throw new IllegalStateException("Api Document is not available "
                    + "you need to provide dbId/dbRegion/username/password at initialization.");
        }
        return stargateClient.apiDocument();
    }
    
    /** 
     * Rest Api. 
     * 
     * @return ApiRestClient
     */
    public StargateRestApiClient apiStargateData() {
        if (stargateClient == null) {
            throw new IllegalStateException("Api Rest is not available "
                    + "you need to provide dbId/dbRegion/username/password at initialization.");
        }
        return stargateClient.apiRest();
    }
    
    /** 
     * GraphQL Api. 
     * 
     * @return ApiGraphQLClient
     */
    public StargateGraphQLApiClient apiStargateGraphQL() {
        if (stargateClient == null) {
            throw new IllegalStateException("GraphQL Api is not available "
                    + "you need to provide dbId/dbRegion/token at initialization.");
        }
        return stargateClient.apiGraphQL();
    }
    
    /**
     * Integration with grpc Api in Stargate.
     *
     * @return
     *      grpc Stargate API.
     */
    public StargateGrpcApiClient apiStargateGrpc() {
        if (stargateClient == null) {
            throw new IllegalStateException("GRPC Api is not available "
                    + "you need to provide dbId/dbRegion/token at initialization.");
        }
        return stargateClient.apiGrpc();
    }
    
    /**
     * Devops API
     * 
     * @return ApiDevopsClient
     */
    public AstraDevopsApiClient apiDevops() {
        if (apiDevops == null) {
            throw new IllegalStateException("Api Devops is not available "
                    + "you need to provide a astra Token (AstraCS:...) at initialization.");
        }
        return apiDevops;
    }
    
    /**
     * Devops API
     * 
     * @return ApiDevopsClient
     */
    public AstraDbClient apiDevopsDatabases() {
        if (apiDevopsDatabases == null) {
            throw new IllegalStateException("Api Devops is not available "
                    + "you need to provide clientId/clientName/clientSecret at initialization.");
        }
        return apiDevopsDatabases;
    }
    
    
    /**
     * Devops API Streaming
     * 
     * @return ApiDevopsClient
     */
    public AstraStreamingClient apiDevopsStreaming() {
        if (apiDevopsStreaming == null) {
            throw new IllegalStateException("Api Devops is not available "
                    + "you need to provide clientId/clientName/clientSecret at initialization.");
        }
        return apiDevopsStreaming;
    }
    
    /**
     * CQL API
     * 
     * @return CqlSession
     */
    public CqlSession cqlSession() {
        if (stargateClient == null || !stargateClient.cqlSession().isPresent()) {
            throw new IllegalStateException("CQL Session is not available."
                    + " Make sure you enabled it with .enableCql() and provide all"
                    + " expected parameters: keyspace, contact points or SCB, user+password ");
        }
        return stargateClient.cqlSession().get();
    }
    
    /**
     * Give access to token.
     * 
     * @return
     *      token value
     */
    public Optional getToken() {
        return Optional.ofNullable(astraClientConfig.getToken());
    }
    
    /**
     * Getter to the configuration, it should not be changed.
     * 
     * @return
     *      initial configuration
     */
    public AstraClientConfig getConfig() {
        return this.astraClientConfig;
    }
    
    /**
     * Change region the application is working on.
     * 
     * @param region
     *      new region
     */
    public void useRegion(String region) {
        LOGGER.info("Switch to region : {}", region);
        this.currentDatabaseRegion = region;
        this.stargateClient.setCurrentDatacenter(region);
        this.stargateClient.initCqlSession();
    }
    
    /**
     * Builder Pattern
     * 
     * @return AstraClientBuilder
     */
    public static AstraClientConfig builder() {
        return new AstraClientConfig();
    }

    /** {@inheritDoc} */
    @Override
    public void close() {
       if (null != stargateClient) {
           stargateClient.close();
       }
    }

    /**
     * Getter accessor for attribute 'stargateClient'.
     *
     * @return
     *       current value of 'stargateClient'
     */
    public StargateClient getStargateClient() {
        return stargateClient;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy