diff --git a/pom.xml b/pom.xml index ae4da5d3..e8366a53 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,8 @@ 33.4.8-jre 1.21.2 3.50.3.0 + + true 4.6 3.6.0 @@ -420,6 +422,23 @@ com.fasterxml.jackson.dataformat jackson-dataformat-csv + + + com.google.code.gson + gson + + + + io.gsonfire + gson-fire + 1.9.0 + + + + org.apache.oltu.oauth2 + org.apache.oltu.oauth2.client + 1.0.2 + org.projectlombok lombok @@ -503,6 +522,22 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + + ${docker.host} + + + false + + + com.mycila license-maven-plugin @@ -519,6 +554,7 @@ + true
LICENSE_HEADER
@@ -579,6 +615,31 @@ + + windows + + + windows + + + + + npipe:////./pipe/docker_engine + + + + non-windows + + + !windows + + + + + ${env.DOCKER_HOST} + + owasp-dependency-check diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java b/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java index 45a229a8..38cd3069 100644 --- a/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java +++ b/src/main/java/eu/openanalytics/containerproxy/auth/AuthenticationBackendFactory.java @@ -26,6 +26,7 @@ import eu.openanalytics.containerproxy.auth.impl.OpenIDAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.SAMLAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.SimpleAuthenticationBackend; +import eu.openanalytics.containerproxy.auth.impl.SpcsAuthenticationBackend; import eu.openanalytics.containerproxy.auth.impl.WebServiceAuthenticationBackend; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AbstractFactoryBean; @@ -74,6 +75,7 @@ protected IAuthenticationBackend createInstance() { case OpenIDAuthenticationBackend.NAME -> backend = new OpenIDAuthenticationBackend(); case WebServiceAuthenticationBackend.NAME -> backend = new WebServiceAuthenticationBackend(environment); case CustomHeaderAuthenticationBackend.NAME -> backend = new CustomHeaderAuthenticationBackend(environment, applicationEventPublisher); + case SpcsAuthenticationBackend.NAME -> backend = new SpcsAuthenticationBackend(environment, applicationEventPublisher); case SAMLAuthenticationBackend.NAME -> { return samlBackend; } diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java new file mode 100644 index 00000000..732b01e8 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/SpcsAuthenticationBackend.java @@ -0,0 +1,129 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl; + +import eu.openanalytics.containerproxy.auth.IAuthenticationBackend; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationFilter; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.core.env.Environment; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; + +import java.util.Map; + +/** + * Authentication backend for SPCS authentication. + * + * This backend authenticates users based on HTTP headers that Snowflake forwards to services + * running inside SPCS containers via ingress. + * + * When a service is configured with executeAsCaller: true in its service specification, + * Snowflake inserts the following headers in every incoming request: + * - Sf-Context-Current-User: The username of the calling user + * - Sf-Context-Current-User-Token: A token representing the calling user's context + * + * The Sf-Context-Current-User-Token is automatically passed to child container services as + * an HTTP header (Sf-Context-Current-User-Token) via ProxyMappingManager, allowing child + * containers to access the caller's rights token for connecting to Snowflake. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/additional-considerations-services-jobs#configuring-caller-s-rights-for-your-service + * + * This backend can only be used when running inside SPCS (detected by + * SNOWFLAKE_SERVICE_NAME environment variable). + * + * Note: ShinyProxy's SPCS backend automatically configures executeAsCaller: true for all services + * (see SpcsBackend.buildServiceSpecYaml). + * + * Configuration: + * proxy.authentication: spcs + */ +public class SpcsAuthenticationBackend implements IAuthenticationBackend { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationBackend.class); + + public static final String NAME = "spcs"; + + private final SpcsAuthenticationFilter filter; + + public SpcsAuthenticationBackend(Environment environment, ApplicationEventPublisher applicationEventPublisher) { + // Verify we're running inside SPCS + String snowflakeServiceName = environment.getProperty("SNOWFLAKE_SERVICE_NAME"); + boolean runningInsideSpcs = snowflakeServiceName != null && !snowflakeServiceName.isEmpty(); + + if (!runningInsideSpcs) { + throw new IllegalStateException( + "SpcsAuthenticationBackend can only be used when running inside SPCS. " + + "SNOWFLAKE_SERVICE_NAME environment variable not found."); + } + + logger.info("Initializing SPCS authentication backend (SNOWFLAKE_SERVICE_NAME: {})", snowflakeServiceName); + + // Create authentication provider and filter + ProviderManager providerManager = new ProviderManager(new SpcsAuthenticationProvider(environment)); + filter = new SpcsAuthenticationFilter(providerManager, applicationEventPublisher); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public boolean hasAuthorization() { + return true; + } + + @Override + public void configureHttpSecurity(HttpSecurity http) throws Exception { + http.formLogin(AbstractHttpConfigurer::disable); + + http.addFilterBefore(filter, AnonymousAuthenticationFilter.class) + .exceptionHandling(e -> { + // Empty configuration - the filter handles all authentication exceptions directly by returning + // error responses and stopping the filter chain. This ensures no default Spring Security + // exception handling (like redirects) occurs if any AuthenticationException somehow escapes. + }); + } + + @Override + public void configureAuthenticationManagerBuilder(AuthenticationManagerBuilder auth) throws Exception { + // Nothing to do - authentication is handled by the filter + } + + @Override + public void customizeContainerEnv(Authentication user, Map env) { + // SPCS user token is passed as HTTP header per request, not as environment variable + // See ProxyMappingManager.dispatchAsync() for header forwarding logic + } + + @Override + public String getLogoutSuccessURL() { + return "/logout-success"; + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java new file mode 100644 index 00000000..1ee85d3e --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationException.java @@ -0,0 +1,31 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import org.springframework.security.access.AccessDeniedException; + +public class SpcsAuthenticationException extends AccessDeniedException { + + public SpcsAuthenticationException(String explanation) { + super(explanation); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java new file mode 100644 index 00000000..f6dfbfa9 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationFilter.java @@ -0,0 +1,163 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +import org.springframework.security.web.util.matcher.OrRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Nonnull; +import java.io.IOException; + +/** + * Authentication filter for SPCS authentication. + * Reads the Snowflake username from the Sf-Context-Current-User HTTP header + * that Snowflake inserts when executeAsCaller: true is configured. + * This filter only works when running inside Snowflake SPCS containers. + */ +public class SpcsAuthenticationFilter extends OncePerRequestFilter { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationFilter.class); + + // Prevent re-authentication on logout-success page and static resources + private static final RequestMatcher REQUEST_MATCHER = new NegatedRequestMatcher(new OrRequestMatcher( + new AntPathRequestMatcher("/logout-success"), + new AntPathRequestMatcher("/webjars/**"), + new AntPathRequestMatcher("/css/**") + )); + + private static final String SPCS_INGRESS_USERNAME_HEADER = "Sf-Context-Current-User"; + private static final String SPCS_INGRESS_USERTOKEN_HEADER = "Sf-Context-Current-User-Token"; + + private final AuthenticationManager authenticationManager; + private final ApplicationEventPublisher eventPublisher; + + public SpcsAuthenticationFilter( + AuthenticationManager authenticationManager, + ApplicationEventPublisher eventPublisher) { + this.authenticationManager = authenticationManager; + this.eventPublisher = eventPublisher; + } + + @Override + protected void doFilterInternal(@Nonnull HttpServletRequest request, + @Nonnull HttpServletResponse response, + @Nonnull FilterChain chain) throws ServletException, IOException { + + if (!REQUEST_MATCHER.matches(request)) { + chain.doFilter(request, response); + return; + } + + try { + // Get the username from Sf-Context-Current-User header (always present when running inside SPCS) + String spcsIngressUserName = request.getHeader(SPCS_INGRESS_USERNAME_HEADER); + + // Get the user token (Sf-Context-Current-User-Token) if available (only when executeAsCaller=true) + String spcsIngressUserToken = request.getHeader(SPCS_INGRESS_USERTOKEN_HEADER); + + if (spcsIngressUserName == null || spcsIngressUserName.isBlank()) { + // Header is required - SPCS always adds this header to all requests when running inside SPCS + // Fail authentication if header is missing + throw new SpcsAuthenticationException("Required header " + SPCS_INGRESS_USERNAME_HEADER + " not found in request"); + } + + // Check if already authenticated with SPCS + // This validation prevents session hijacking and ensures consistency: + // - Security: Prevents an attacker from switching users mid-session by manipulating headers + // - Performance: Avoids re-authenticating on every request once already authenticated + // - Consistency: Ensures the session user matches the current request headers + Authentication existingAuthentication = SecurityContextHolder.getContext().getAuthentication(); + if (existingAuthentication instanceof SpcsAuthenticationToken) { + // Compare the username in the current request header with the username from the existing session + // If they don't match, throw an exception (potential session hijacking or user switch) + if (!existingAuthentication.getPrincipal().equals(spcsIngressUserName)) { + throw new SpcsAuthenticationException( + String.format("Username in header does not match existing session '%s'", + existingAuthentication.getPrincipal())); + } else { + // They match - user is already authenticated with the same identity + // Continue the request without re-authenticating (performance optimization) + chain.doFilter(request, response); + return; + } + } + + // Create authentication token with username and token (token may be null) + SpcsAuthenticationToken authRequest = new SpcsAuthenticationToken( + spcsIngressUserName, + spcsIngressUserToken, + new WebAuthenticationDetailsSource().buildDetails(request) + ); + + // Authenticate + Authentication authResult = authenticationManager.authenticate(authRequest); + if (authResult == null) { + throw new SpcsAuthenticationException("No authentication result"); + } + + // Set in security context + SecurityContextHolder.getContext().setAuthentication(authResult); + eventPublisher.publishEvent(new AuthenticationSuccessEvent(authResult)); + logger.debug("Successfully authenticated SPCS user: {}", spcsIngressUserName); + + } catch (SpcsAuthenticationException e) { + logger.warn("SPCS authentication failed: {}", e.getMessage()); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write("SPCS authentication failed: " + e.getMessage()); + return; + } catch (AuthenticationException e) { + logger.warn("SPCS authentication failed", e); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.getWriter().write("SPCS authentication failed: " + e.getMessage()); + return; + } catch (Exception e) { + logger.warn("Unexpected error during SPCS authentication", e); + SecurityContextHolder.clearContext(); + // Don't continue the filter chain - fail the request + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + response.getWriter().write("Unexpected error during SPCS authentication"); + return; + } + + chain.doFilter(request, response); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java new file mode 100644 index 00000000..36681d8f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationProvider.java @@ -0,0 +1,295 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.api.StatementsApi; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSet; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class SpcsAuthenticationProvider implements AuthenticationProvider { + + private static final Logger logger = LoggerFactory.getLogger(SpcsAuthenticationProvider.class); + private static final String USER_AGENT = "ContainerProxy/1.2.2"; + + private final Set adminGroups; + private final Environment environment; + private final String computeWarehouse; + + public SpcsAuthenticationProvider(Environment environment) { + this.environment = environment; + // Load admin groups from environment (same logic as UserService.init()) + this.adminGroups = new HashSet<>(); + + // Support for old, non-array notation + String singleGroup = environment.getProperty("proxy.admin-groups"); + if (singleGroup != null && !singleGroup.isEmpty()) { + adminGroups.add(singleGroup.toUpperCase()); + } + + for (int i = 0; ; i++) { + String groupName = environment.getProperty(String.format("proxy.admin-groups[%s]", i)); + if (groupName == null || groupName.isEmpty()) { + break; + } + adminGroups.add(groupName.toUpperCase()); + } + + // Load optional compute warehouse for SPCS authentication admin check + this.computeWarehouse = environment.getProperty("proxy.spcs.compute-warehouse"); + if (computeWarehouse != null && !computeWarehouse.isEmpty()) { + logger.debug("SPCS compute warehouse configured for admin role validation: {}", computeWarehouse); + } + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + SpcsAuthenticationToken authRequest = (SpcsAuthenticationToken) authentication; + + if (authRequest.isValid()) { + String spcsIngressUserToken = authRequest.getCredentials() != null ? authRequest.getCredentials().toString() : null; + + Collection authorities = new ArrayList<>(); + + // Check conditions that would skip admin role validation (guard clauses) + if (adminGroups.isEmpty()) { + logger.debug("No admin groups configured, skipping admin role check"); + } else if (computeWarehouse == null || computeWarehouse.isEmpty()) { + logger.debug("Compute warehouse not configured (proxy.spcs.compute-warehouse), skipping admin role check"); + } else if (spcsIngressUserToken == null || spcsIngressUserToken.isBlank()) { + logger.debug("User token not available (executeAsCaller may not be enabled), skipping admin role check"); + } else { + // All conditions met: perform admin role validation + // Requires: user token, admin groups, and compute warehouse + logger.debug("User token available, checking admin roles for {} admin groups using warehouse {}", adminGroups.size(), computeWarehouse); + Set userAdminGroups = validateAdminRoles(spcsIngressUserToken); + logger.debug("User has {} admin roles out of {} configured", userAdminGroups.size(), adminGroups.size()); + for (String adminGroup : userAdminGroups) { + // Format: ROLE_GROUPNAME (UserService.getGroups() strips the "ROLE_" prefix) + String roleName = adminGroup.startsWith("ROLE_") ? adminGroup : "ROLE_" + adminGroup; + authorities.add(new SimpleGrantedAuthority(roleName)); + } + } + + return new SpcsAuthenticationToken( + authRequest.getPrincipal().toString(), + spcsIngressUserToken, + authorities, + authRequest.getDetails(), + true + ); + } + + throw new SpcsAuthenticationException("Invalid Snowflake username"); + } + + /** + * Validates which admin roles the user has by calling IS_ROLE_IN_SESSION() for all admin groups in a single SQL query. + * Uses the Sf-Context-Current-User-Token to authenticate as the caller. + * + * @param userToken The Sf-Context-Current-User-Token + * @return Set of admin group names that the user has in their session + */ + private Set validateAdminRoles(String userToken) { + Set userAdminGroups = new HashSet<>(); + + if (adminGroups.isEmpty()) { + return userAdminGroups; + } + + try { + // Get account URL from environment + String accountUrl = getAccountUrl(); + if (accountUrl == null) { + logger.warn("Cannot validate admin roles: account URL not available"); + return userAdminGroups; + } + + // Create a new API client instance (not shared) with user token as bearer token + // Use KeyPair authentication scheme (HttpBearerAuth) - works for OAuth tokens from SPCS ingress + ApiClient apiClient = new ApiClient(); + apiClient.setBasePath(accountUrl); + + HttpBearerAuth bearerAuth = (HttpBearerAuth) apiClient.getAuthentication("KeyPair"); + + // SPCS authentication requires combined token format: . + // Read service OAuth token from file and combine with user token + String serviceToken = readSpcsSessionTokenFromFile(); + if (serviceToken == null || serviceToken.isEmpty()) { + logger.warn("Service OAuth token not available from file for admin role validation"); + return userAdminGroups; + } + + // Format: . + String combinedToken = serviceToken + "." + userToken; + bearerAuth.setBearerToken(combinedToken); + + // using SQL statement endpoint. there maybe a REST API for this in the future. + StatementsApi statementsApi = new StatementsApi(apiClient); + + // Build a single SQL query with one column per admin group using IS_ROLE_IN_SESSION() + // Example: SELECT IS_ROLE_IN_SESSION('ROLE1') AS role1, IS_ROLE_IN_SESSION('ROLE2') AS role2, ... + StringBuilder sqlBuilder = new StringBuilder("SELECT "); + List adminGroupList = new ArrayList<>(adminGroups); + for (int i = 0; i < adminGroupList.size(); i++) { + if (i > 0) { + sqlBuilder.append(", "); + } + String adminGroup = adminGroupList.get(i).toUpperCase(); + sqlBuilder.append("IS_ROLE_IN_SESSION('").append(escapeSqlString(adminGroup)).append("') AS role_").append(i); + } + String sql = sqlBuilder.toString(); + + // Prepare request outside try so it is available in catch/retry + SubmitStatementRequest request = new SubmitStatementRequest(); + request.setStatement(sql); + // Set warehouse for SQL execution + request.setWarehouse(computeWarehouse.toUpperCase()); + + try { + + ResultSet result = statementsApi.submitStatement( + USER_AGENT, + request, + null, // requestId + false, // async + false, // nullable + null, // accept + "OAUTH" // xSnowflakeAuthorizationTokenType: OAuth token from SPCS ingress + ); + + // Parse result: Each column contains TRUE or FALSE for the corresponding admin group + // ResultSet.data is List>, first row contains all the boolean values + if (result.getData() != null && !result.getData().isEmpty()) { + List firstRow = result.getData().get(0); + if (firstRow != null && firstRow.size() == adminGroupList.size()) { + for (int i = 0; i < firstRow.size(); i++) { + String value = firstRow.get(i); + // Snowflake returns "true" or "false" as strings + if ("true".equalsIgnoreCase(value) || "TRUE".equals(value)) { + String adminGroup = adminGroupList.get(i); + userAdminGroups.add(adminGroup); + logger.debug("User has admin role: {}", adminGroup); + } + } + } else { + logger.warn("Unexpected result format: expected {} columns but got {}", + adminGroupList.size(), firstRow != null ? firstRow.size() : 0); + } + } + } catch (ApiException e) { + // Log error details: exception includes message and stack trace + logger.warn("Failed to check admin roles (user will not have admin privileges): code={}", + e.getCode(), e); + // Return empty admin groups on failure (no fallback) + return userAdminGroups; + } + } catch (Exception e) { + logger.error("Error validating admin roles: {}", e.getMessage(), e); + // Return empty admin groups on exception (no fallback) + return userAdminGroups; + } + + return userAdminGroups; + } + + /** + * Reads the SPCS session token from the standard file location if available. + * @return The token string or null if not available. + */ + private String readSpcsSessionTokenFromFile() { + try { + Path tokenPath = Paths.get("/snowflake/session/token"); + if (Files.exists(tokenPath) && Files.isRegularFile(tokenPath)) { + String token = Files.readString(tokenPath).trim(); + if (!token.isEmpty()) { + return token; + } else { + logger.warn("SPCS session token file exists but is empty: {}", tokenPath); + } + } + } catch (Exception ex) { + logger.warn("Error reading SPCS session token from file: {}", ex.getMessage()); + } + return null; + } + + /** + * Gets the Snowflake account URL from environment variables. + * + * @return Account URL or null if not available + */ + private String getAccountUrl() { + // Check SNOWFLAKE_HOST first (preferred when running inside SPCS) + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + return snowflakeHost; + } else { + return "https://" + snowflakeHost; + } + } + + // Fall back to constructing from SNOWFLAKE_ACCOUNT + String snowflakeAccount = environment.getProperty("SNOWFLAKE_ACCOUNT"); + if (snowflakeAccount != null && !snowflakeAccount.isEmpty()) { + return String.format("https://%s.snowflakecomputing.com", snowflakeAccount); + } + + return null; + } + + /** + * Escapes single quotes in SQL string literals. + * + * @param value The string value to escape + * @return Escaped string safe for use in SQL string literal + */ + private String escapeSqlString(String value) { + // Escape single quotes by doubling them: ' -> '' + return value.replace("'", "''"); + } + + @Override + public boolean supports(Class authentication) { + return SpcsAuthenticationToken.class.isAssignableFrom(authentication); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java new file mode 100644 index 00000000..c0cb5b49 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/auth/impl/spcs/SpcsAuthenticationToken.java @@ -0,0 +1,82 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.auth.impl.spcs; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.authentication.WebAuthenticationDetails; + +import java.util.Collection; + +public class SpcsAuthenticationToken extends AbstractAuthenticationToken { + + private final String spcsIngressUserName; // Sf-Context-Current-User header value + private final String spcsIngressUserToken; // Sf-Context-Current-User-Token header value + private final WebAuthenticationDetails details; + + public SpcsAuthenticationToken(String spcsIngressUserName, String spcsIngressUserToken, WebAuthenticationDetails details) { + super(null); + this.spcsIngressUserName = spcsIngressUserName; + this.spcsIngressUserToken = spcsIngressUserToken; + this.details = details; + super.setAuthenticated(false); + } + + public SpcsAuthenticationToken(String spcsIngressUserName, String spcsIngressUserToken, Collection authorities, WebAuthenticationDetails details, boolean isAuthenticated) { + super(authorities); + this.spcsIngressUserName = spcsIngressUserName; + this.spcsIngressUserToken = spcsIngressUserToken; + this.details = details; + super.setAuthenticated(isAuthenticated); + } + + public boolean isValid() { + return spcsIngressUserName != null && !spcsIngressUserName.isBlank(); + } + + @Override + public Object getPrincipal() { + return spcsIngressUserName; + } + + @Override + public Object getCredentials() { + // Return the SPCS ingress user token as the credential (proof of identity) + // This follows Spring Security conventions where credentials represent authentication proof + return spcsIngressUserToken; + } + + @Override + public String getName() { + return this.spcsIngressUserName; + } + + @Override + public WebAuthenticationDetails getDetails() { + return this.details; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) { + throw new SpcsAuthenticationException("Cannot change authenticated after initialization!"); + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java new file mode 100644 index 00000000..a63dd04f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsBackend.java @@ -0,0 +1,1962 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.api.ServiceApi; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceEndpoint; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpecInlineText; +import com.google.gson.reflect.TypeToken; +import eu.openanalytics.containerproxy.ContainerFailedToStartException; +import eu.openanalytics.containerproxy.backend.AbstractContainerBackend; +import eu.openanalytics.containerproxy.event.NewProxyEvent; +import eu.openanalytics.containerproxy.model.runtime.Container; +import eu.openanalytics.containerproxy.model.runtime.ExistingContainerInfo; +import eu.openanalytics.containerproxy.model.runtime.PortMappings; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.model.runtime.ProxyStartupLog; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerName; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerNameKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ContainerImageKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.HttpHeaders; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.HttpHeadersKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.InstanceIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ProxyIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.ProxySpecIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RealmIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.UserIdKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValue; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValueKey; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.RuntimeValueKeyRegistry; +import eu.openanalytics.containerproxy.model.spec.ContainerSpec; +import eu.openanalytics.containerproxy.model.spec.ProxySpec; +import eu.openanalytics.containerproxy.spec.IProxySpecProvider; +import eu.openanalytics.containerproxy.util.EnvironmentUtils; +import eu.openanalytics.containerproxy.util.Retrying; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; +import eu.openanalytics.containerproxy.auth.impl.spcs.SpcsAuthenticationToken; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Supplier; +import java.util.stream.Stream; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +@Component +@ConditionalOnProperty(name = "proxy.container-backend", havingValue = "spcs") +public class SpcsBackend extends AbstractContainerBackend { + + private static final String PROPERTY_PREFIX = "proxy.spcs."; + private static final String PROPERTY_ACCOUNT_IDENTIFIER = "account-identifier"; + private static final String PROPERTY_USERNAME = "username"; + private static final String PROPERTY_PROGRAMMATIC_ACCESS_TOKEN = "programmatic-access-token"; + private static final String PROPERTY_PRIVATE_RSA_KEY_PATH = "private-rsa-key-path"; + private static final String PROPERTY_DATABASE = "database"; + private static final String PROPERTY_SCHEMA = "schema"; + private static final String PROPERTY_COMPUTE_POOL = "compute-pool"; + private static final String PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS = "external-access-integrations"; + private static final String PROPERTY_SERVICE_WAIT_TIME = "service-wait-time"; + + private ServiceApi snowflakeServiceAPI; + private ApiClient snowflakeAPIClient; + private int serviceWaitTime; + private String database; + private String schema; + private String computePool; + private List externalAccessIntegrations; + private String accountUrl; + private String accountIdentifier; // Account identifier (e.g., "ORG-ACCOUNT" or "ACCOUNT") - stored separately from URL + private String username; + private AuthMethod authMethod; + private String privateRsaKeyPath; // For keypair authentication - path to RSA private key + private Supplier jwtTokenSupplier; // Supplier to generate/regenerate JWT tokens for keypair auth + + private static final Path SPCS_SESSION_TOKEN_PATH = Paths.get("/snowflake/session/token"); + + private enum AuthMethod { + SPCS_SESSION_TOKEN, // Running inside SPCS, token from /snowflake/session/token + KEYPAIR, // Username + private RSA key + PAT // Username + PAT token + } + + @Inject + private IProxySpecProvider proxySpecProvider; + + + @Override + @PostConstruct + public void initialize() { + super.initialize(); + + // Detect if running inside SPCS by checking SNOWFLAKE_SERVICE_NAME environment variable + String snowflakeServiceName = environment.getProperty("SNOWFLAKE_SERVICE_NAME"); + boolean runningInsideSpcs = snowflakeServiceName != null && !snowflakeServiceName.isEmpty(); + + if (runningInsideSpcs) { + loadConfigurationFromEnvironment(); + setupSpcsSessionTokenAuth(); + } else { + loadConfigurationFromProperties(); + setupExternalAuth(); + } + + serviceWaitTime = environment.getProperty(PROPERTY_PREFIX + PROPERTY_SERVICE_WAIT_TIME, Integer.class, 180000); + + initializeSnowflakeAPIClient(); + + // Validate specs + for (ProxySpec spec : proxySpecProvider.getSpecs()) { + ContainerSpec containerSpec = spec.getContainerSpecs().get(0); + if (!containerSpec.getMemoryRequest().isOriginalValuePresent()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has no 'memory-request' configured, this is required for running on Snowflake SPCS", spec.getId())); + } + if (!containerSpec.getCpuRequest().isOriginalValuePresent()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has no 'cpu-request' configured, this is required for running on Snowflake SPCS", spec.getId())); + } + if (containerSpec.getMemoryLimit().isOriginalValuePresent()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has 'memory-limit' configured, this is not supported by Snowflake SPCS", spec.getId())); + } + if (containerSpec.getCpuLimit().isOriginalValuePresent()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has 'cpu-limit' configured, this is not supported by Snowflake SPCS", spec.getId())); + } + if (containerSpec.isPrivileged()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has 'privileged: true' configured, this is not supported by Snowflake SPCS", spec.getId())); + } + if (containerSpec.getVolumes().isOriginalValuePresent() && !containerSpec.getVolumes().getOriginalValue().isEmpty()) { + throw new IllegalStateException(String.format("Error in configuration of specs: spec with id '%s' has 'volumes' configured, this is not yet supported by Snowflake SPCS", spec.getId())); + } + } + } + + + /** + * Loads configuration from Snowflake environment variables (when running inside SPCS). + */ + private void loadConfigurationFromEnvironment() { + log.info("Detected running inside SPCS (SNOWFLAKE_SERVICE_NAME: {})", environment.getProperty("SNOWFLAKE_SERVICE_NAME")); + + // Load Snowflake environment variables + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + String snowflakeAccount = environment.getProperty("SNOWFLAKE_ACCOUNT"); + String snowflakeDatabase = environment.getProperty("SNOWFLAKE_DATABASE"); + String snowflakeSchema = environment.getProperty("SNOWFLAKE_SCHEMA"); + String snowflakeRegion = environment.getProperty("SNOWFLAKE_REGION"); + String snowflakeComputePool = environment.getProperty("SNOWFLAKE_COMPUTE_POOL"); + + // Get account identifier from SNOWFLAKE_ACCOUNT (required) + if (snowflakeAccount == null || snowflakeAccount.isEmpty()) { + throw new IllegalStateException("Error in SPCS environment: SNOWFLAKE_ACCOUNT not set"); + } + accountIdentifier = snowflakeAccount; + + // Use SNOWFLAKE_HOST if available, otherwise build from account identifier + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + // SNOWFLAKE_HOST contains the full hostname (e.g., ".us-east-1.snowflakecomputing.com") + // Add https:// if not present + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + accountUrl = snowflakeHost; + } else { + accountUrl = "https://" + snowflakeHost; + } + log.info("Using account URL from SNOWFLAKE_HOST environment variable: {}", accountUrl); + } else { + // Build account URL from account identifier by appending .snowflakecomputing.com + // Format: https://{account_identifier}.snowflakecomputing.com + accountUrl = String.format("https://%s.snowflakecomputing.com", accountIdentifier); + } + + // Use database and schema from environment variables (available when running inside SPCS) + if (snowflakeDatabase != null && !snowflakeDatabase.isEmpty()) { + database = snowflakeDatabase; + log.info("Using database from SNOWFLAKE_DATABASE environment variable: {}", database); + } else { + database = getProperty(PROPERTY_DATABASE); + if (database == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: SNOWFLAKE_DATABASE not set and proxy.spcs.database not configured"); + } + } + + if (snowflakeSchema != null && !snowflakeSchema.isEmpty()) { + schema = snowflakeSchema; + log.info("Using schema from SNOWFLAKE_SCHEMA environment variable: {}", schema); + } else { + schema = getProperty(PROPERTY_SCHEMA); + if (schema == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: SNOWFLAKE_SCHEMA not set and proxy.spcs.schema not configured"); + } + } + + // Compute pool: use configured value if set, otherwise use SNOWFLAKE_COMPUTE_POOL + computePool = getProperty(PROPERTY_COMPUTE_POOL); + if (computePool == null) { + if (snowflakeComputePool != null && !snowflakeComputePool.isEmpty()) { + computePool = snowflakeComputePool; + log.info("Using compute pool from SNOWFLAKE_COMPUTE_POOL environment variable: {}", computePool); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set and SNOWFLAKE_COMPUTE_POOL environment variable not available"); + } + } else { + log.info("Using compute pool from configuration: {} (SNOWFLAKE_COMPUTE_POOL was: {})", computePool, snowflakeComputePool); + } + + // Load external access integrations (optional, can be null) + externalAccessIntegrations = EnvironmentUtils.readList(environment, PROPERTY_PREFIX + PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS); + if (externalAccessIntegrations != null && !externalAccessIntegrations.isEmpty()) { + log.info("Using external access integrations from configuration: {}", externalAccessIntegrations); + } + + log.info("Loaded SPCS environment: account={}, region={}, compute-pool={}", + snowflakeAccount, snowflakeRegion, computePool); + } + + /** + * Loads configuration from properties (when running external to SPCS). + */ + private void loadConfigurationFromProperties() { + // Get account identifier from property (required when running external to SPCS) + String accountIdentifierConfig = getProperty(PROPERTY_ACCOUNT_IDENTIFIER); + if (accountIdentifierConfig == null || accountIdentifierConfig.isEmpty()) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.account-identifier not set"); + } + accountIdentifier = accountIdentifierConfig; + + // Check for SNOWFLAKE_HOST environment variable for account URL (works both inside and outside SPCS) + String snowflakeHost = environment.getProperty("SNOWFLAKE_HOST"); + if (snowflakeHost != null && !snowflakeHost.isEmpty()) { + // SNOWFLAKE_HOST contains the full hostname + // Add https:// if not present + if (snowflakeHost.startsWith("https://") || snowflakeHost.startsWith("http://")) { + accountUrl = snowflakeHost; + } else { + accountUrl = "https://" + snowflakeHost; + } + log.info("Using account URL from SNOWFLAKE_HOST environment variable: {}", accountUrl); + } else { + // Construct account URL from account identifier by appending .snowflakecomputing.com + accountUrl = String.format("https://%s.snowflakecomputing.com", accountIdentifier); + } + + database = getProperty(PROPERTY_DATABASE); + if (database == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.database not set"); + } + + schema = getProperty(PROPERTY_SCHEMA); + if (schema == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.schema not set"); + } + + computePool = getProperty(PROPERTY_COMPUTE_POOL); + if (computePool == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set"); + } + + // Load external access integrations (optional, can be null) + externalAccessIntegrations = EnvironmentUtils.readList(environment, PROPERTY_PREFIX + PROPERTY_EXTERNAL_ACCESS_INTEGRATIONS); + if (externalAccessIntegrations != null && !externalAccessIntegrations.isEmpty()) { + log.info("Using external access integrations from configuration: {}", externalAccessIntegrations); + } + } + + /** + * Sets up SPCS session token authentication (when running inside SPCS). + */ + private void setupSpcsSessionTokenAuth() { + // Check for session token file + if (!Files.exists(SPCS_SESSION_TOKEN_PATH) || !Files.isRegularFile(SPCS_SESSION_TOKEN_PATH)) { + throw new IllegalStateException("Running inside SPCS but session token file not found: " + SPCS_SESSION_TOKEN_PATH); + } + + // Use supplier to read token fresh on each request (allows SPCS to refresh it automatically) + authMethod = AuthMethod.SPCS_SESSION_TOKEN; + jwtTokenSupplier = () -> { + try { + String sessionToken = Files.readString(SPCS_SESSION_TOKEN_PATH).trim(); + if (sessionToken.isEmpty()) { + throw new IllegalStateException("SPCS session token file exists but is empty: " + SPCS_SESSION_TOKEN_PATH); + } + return sessionToken; + } catch (IOException e) { + throw new RuntimeException("Error reading SPCS session token from " + SPCS_SESSION_TOKEN_PATH + ": " + e.getMessage(), e); + } + }; + log.info("Running inside SPCS: will read authentication token from {} on each request", SPCS_SESSION_TOKEN_PATH); + } + + /** + * Initializes the Snowflake API client with authentication. + */ + private void initializeSnowflakeAPIClient() { + try { + // Create a new API client instance for SPCS backend + snowflakeAPIClient = new ApiClient(); + snowflakeAPIClient.setBasePath(accountUrl); + + // Set authentication token based on auth method + // Use KeyPair authentication scheme (HttpBearerAuth) for all token types - works for JWT, OAuth, and PAT tokens + HttpBearerAuth bearerAuth = (HttpBearerAuth) snowflakeAPIClient.getAuthentication("KeyPair"); + + // Set bearer token using supplier (allows automatic refresh) + // For keypair: use supplier to generate JWT tokens on-demand (auto-refreshes on expiry) + // For SPCS session token: use supplier to read token fresh on each request (allows SPCS auto-refresh) + // For PAT: use supplier for consistency and to support future token rotation + bearerAuth.setBearerToken(jwtTokenSupplier); + + // Set X-Snowflake-Authorization-Token-Type header + // This helps snowflake identify the token type and useful in logs for debugging + String tokenType; + if (authMethod == AuthMethod.KEYPAIR) { + tokenType = "KEYPAIR_JWT"; // Key-pair JWT token + } else if (authMethod == AuthMethod.SPCS_SESSION_TOKEN) { + tokenType = "OAUTH"; // OAuth token from SPCS session + } else if (authMethod == AuthMethod.PAT) { + tokenType = "PROGRAMMATIC_ACCESS_TOKEN"; // Programmatic access token + } else { + throw new IllegalStateException("Unknown authentication method: " + authMethod); + } + snowflakeAPIClient.addDefaultHeader("X-Snowflake-Authorization-Token-Type", tokenType); + + snowflakeServiceAPI = new ServiceApi(snowflakeAPIClient); + log.info("Initialized Snowflake SPCS backend with account URL: {} using authentication type: {}", accountUrl, tokenType); + } catch (Exception e) { + throw new IllegalStateException("Error initializing Snowflake API client: " + e.getMessage(), e); + } + } + + /** + * Sets up external authentication (keypair or PAT) when running external to SPCS. + */ + private void setupExternalAuth() { + username = getProperty(PROPERTY_USERNAME); + + String privateRsaKeyPath = getProperty(PROPERTY_PRIVATE_RSA_KEY_PATH); + String programmaticAccessToken = getProperty(PROPERTY_PROGRAMMATIC_ACCESS_TOKEN); + + if (username == null) { + throw new IllegalStateException("Error in configuration of SPCS backend: proxy.spcs.username not set (required when running external to Snowflake SPCS)"); + } + + if (privateRsaKeyPath != null && Files.exists(Paths.get(privateRsaKeyPath))) { + // Priority 2: Keypair authentication + this.privateRsaKeyPath = privateRsaKeyPath; + authMethod = AuthMethod.KEYPAIR; + // JWT token will be generated on-demand via supplier + // This allows automatic regeneration when the token expires + jwtTokenSupplier = () -> generateJwtTokenForKeypair(); + // For REST API, we'll use the supplier to get fresh JWT tokens + // For ingress, JWT needs to be exchanged for Snowflake Token (handled separately) + log.info("Using keypair authentication for user: {} with RSA key: {}", username, privateRsaKeyPath); + } else if (programmaticAccessToken != null && !programmaticAccessToken.isEmpty()) { + // Priority 3: Programmatic Access Token (PAT) authentication + // Use supplier for consistency and to support future token rotation scenarios + authMethod = AuthMethod.PAT; + final String patToken = programmaticAccessToken; // Final variable for use in lambda + jwtTokenSupplier = () -> patToken; + log.info("Using programmatic access token authentication for user: {}", username); + } else { + throw new IllegalStateException("Error in configuration of SPCS backend: one of the following must be set: proxy.spcs.private-rsa-key-path or proxy.spcs.programmatic-access-token"); + } + } + + + @Override + public Proxy startContainer(Authentication authentication, Container initialContainer, ContainerSpec spec, Proxy proxy, ProxySpec proxySpec, ProxyStartupLog.ProxyStartupLogBuilder proxyStartupLogBuilder) throws ContainerFailedToStartException { + Container.ContainerBuilder rContainerBuilder = initialContainer.toBuilder(); + String containerId = UUID.randomUUID().toString(); + rContainerBuilder.id(containerId); + + SpcsSpecExtension specExtension = proxySpec.getSpecExtension(SpcsSpecExtension.class); + try { + // Build environment variables + Map env = buildEnv(authentication, spec, proxy); + + // Generate service name (must be unique and valid Snowflake identifier) + String serviceName = generateServiceName(proxy.getId(), initialContainer.getIndex()); + + // Build service YAML spec + String serviceSpecYaml = buildServiceSpecYaml(spec, env, specExtension, proxy, serviceName, authentication); + + // Create service spec + ServiceSpecInlineText serviceSpec = new ServiceSpecInlineText(); + serviceSpec.setSpecType("from_inline"); // Set discriminator value for polymorphic type + serviceSpec.setSpecText(serviceSpecYaml); + + // Create service + Service service = new Service(); + service.setName(serviceName); + service.setComputePool(specExtension.getSpcsComputePool().getValueOrDefault(computePool)); + service.setSpec(serviceSpec); + + // Set external access integrations: use spec-level if specified, otherwise use global config + List externalAccessIntegrations = specExtension.getSpcsExternalAccessIntegrations().getValueOrNull(); + if (externalAccessIntegrations == null || externalAccessIntegrations.isEmpty()) { + externalAccessIntegrations = this.externalAccessIntegrations; + } + if (externalAccessIntegrations != null && !externalAccessIntegrations.isEmpty()) { + service.setExternalAccessIntegrations(externalAccessIntegrations); + } + + // Store runtime values in comment field for recovery (similar to Docker labels) + // This allows automatic parsing during recovery using parseCommentAsRuntimeValues() + // proxy-id and container-index are also included for convenience (they're also in service name) + // Note: Some values can't be stored here: + // - image: stored in service spec (YAML), extracted during recovery + Map commentMetadata = new HashMap<>(); + + // Store all runtime values that should be included for recovery + Stream.concat( + proxy.getRuntimeValues().values().stream(), + initialContainer.getRuntimeValues().values().stream() + ).forEach(runtimeValue -> { + if (runtimeValue.getKey().getIncludeAsLabel() || runtimeValue.getKey().getIncludeAsAnnotation()) { + commentMetadata.put(runtimeValue.getKey().getKeyAsLabel(), runtimeValue.toString()); + } + }); + + String comment = JSON.getGson().toJson(commentMetadata); + service.setComment(comment); + + // Tell the status service we are starting the container + proxyStartupLogBuilder.startingContainer(initialContainer.getIndex()); + + // Create the service + String fullServiceName = database + "." + schema + "." + serviceName; + try { + snowflakeServiceAPI.createService(database, schema, service, "ifNotExists"); + slog.info(proxy, String.format("Created Snowflake service: %s", fullServiceName)); + } catch (ApiException e) { + if (e.getCode() != 409) { // 409 = conflict, which is OK if service exists + throw new ContainerFailedToStartException("Failed to create Snowflake service: " + e.getMessage(), e, rContainerBuilder.build()); + } + } + + rContainerBuilder.addRuntimeValue(new RuntimeValue(BackendContainerNameKey.inst, new BackendContainerName(fullServiceName)), false); + applicationEventPublisher.publishEvent(new NewProxyEvent(proxy.toBuilder().updateContainer(rContainerBuilder.build()).build(), authentication)); + + // Wait for service to be ready (and endpoints if running external to SPCS) + boolean needsEndpoints = !isRunningInsideSpcs() && spec.getPortMapping() != null && !spec.getPortMapping().isEmpty(); + String waitMessage = needsEndpoints ? "SPCS Service and Endpoints" : "SPCS Service"; + + boolean serviceReady = Retrying.retry((currentAttempt, maxAttempts) -> { + try { + // Check if service containers are running/ready + List containers = snowflakeServiceAPI.listServiceContainers(database, schema, serviceName); + boolean serviceRunning = false; + if (containers != null && !containers.isEmpty()) { + // Check if any container is running/ready + for (ServiceContainer serviceContainer : containers) { + String status = serviceContainer.getStatus(); + String serviceStatus = serviceContainer.getServiceStatus(); + if (status != null && (status.equals("RUNNING") || status.equals("UP") || status.equals("READY"))) { + serviceRunning = true; + break; + } + if (serviceStatus != null && (serviceStatus.equals("RUNNING") || serviceStatus.equals("UP") || serviceStatus.equals("READY"))) { + serviceRunning = true; + break; + } + if (status != null && (status.equals("FAILED") || status.equals("ERROR"))) { + slog.warn(proxy, String.format("SPCS service container failed: status=%s, message=%s", status, serviceContainer.getMessage())); + return new Retrying.Result(false, false); + } + } + } + + // If service is not running yet, keep waiting + if (!serviceRunning) { + return Retrying.FAILURE; + } + + // If running external to SPCS, also check endpoints are ready + if (needsEndpoints) { + List endpoints = snowflakeServiceAPI.showServiceEndpoints(database, schema, serviceName); + if (endpoints == null || endpoints.isEmpty()) { + return Retrying.FAILURE; + } + + // Check if all expected endpoints have valid ingress URLs + for (eu.openanalytics.containerproxy.model.spec.PortMapping portMapping : spec.getPortMapping()) { + boolean foundValidEndpoint = false; + for (ServiceEndpoint endpoint : endpoints) { + if (endpoint.getPort() != null && endpoint.getPort().equals(portMapping.getPort()) && + endpoint.getIsPublic() != null && endpoint.getIsPublic() && + "HTTP".equalsIgnoreCase(endpoint.getProtocol())) { + String ingressUrl = endpoint.getIngressUrl(); + if (ingressUrl != null && !ingressUrl.isEmpty() && + !ingressUrl.toLowerCase().contains("provisioning") && + !ingressUrl.toLowerCase().contains("progress") && + (ingressUrl.contains("://") || ingressUrl.contains("."))) { + foundValidEndpoint = true; + break; + } + } + } + if (!foundValidEndpoint) { + return Retrying.FAILURE; + } + } + } + + // Both service and endpoints (if needed) are ready + return Retrying.SUCCESS; + } catch (ApiException e) { + slog.warn(proxy, String.format("Error checking service status: %s", e.getMessage())); + return Retrying.FAILURE; + } + }, serviceWaitTime, waitMessage, 10, proxy, slog); + + if (!serviceReady) { + // Try to fetch and include logs in error message + String logInfo = fetchServiceLogsForError(database, schema, serviceName); + String errorMessage = "Service failed to start" + (needsEndpoints ? " or endpoints failed to provision" : ""); + if (logInfo != null && !logInfo.isEmpty()) { + // Log the container logs separately so they appear in the log output before service deletion + slog.warn(proxy, String.format("Container logs for failed service %s:\n%s", serviceName, logInfo)); + errorMessage += ". Container logs: " + logInfo; + } + throw new ContainerFailedToStartException(errorMessage, null, rContainerBuilder.build()); + } + + proxyStartupLogBuilder.containerStarted(initialContainer.getIndex()); + + // Get service image info (from service spec) + rContainerBuilder.addRuntimeValue(new RuntimeValue(ContainerImageKey.inst, spec.getImage().getValue()), false); + + Proxy.ProxyBuilder proxyBuilder = proxy.toBuilder(); + Map portBindings = new HashMap<>(); + Container rContainer = rContainerBuilder.build(); + Map targets = setupPortMappingExistingProxy(proxy, rContainer, portBindings); + proxyBuilder.addTargets(targets); + + // when forwarding HTTP requests to SPCS we need to switch from "Bearer" authorization used on REST API to "Snowflake Token" authorization + // Extract endpoint URL from targets for keypair auth token exchange scope + // TODO: how do we refresh the short lived "Snowflake Token" after the proxy has been running for a while? + String endpointUrl = extractEndpointUrlFromTargets(targets); + + Map headers = setupProxyContainerHTTPHeaders(proxy, endpointUrl, authentication); + proxyBuilder.addRuntimeValue(new RuntimeValue(HttpHeadersKey.inst, new HttpHeaders(headers)), true); + proxyBuilder.updateContainer(rContainer); + return proxyBuilder.build(); + } catch (ContainerFailedToStartException t) { + throw t; + } catch (InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + throw new ContainerFailedToStartException("SPCS container failed to start", interruptedException, rContainerBuilder.build()); + } catch (Throwable throwable) { + throw new ContainerFailedToStartException("SPCS container failed to start", throwable, rContainerBuilder.build()); + } + } + + private String generateServiceName(String proxyId, Integer containerIndex) { + // Snowflake service names must be valid identifiers (alphanumeric and underscore) + // Use uppercase to match Snowflake's behavior and avoid case sensitivity issues + // Pattern: SP_SERVICE____ + // Use double underscores as separators for easier parsing + // Replace dashes (from UUID format) with single underscores for exact recovery + // Note: proxyId is expected to be a UUID (alphanumeric + hyphens only) + String normalizedProxyId = proxyId.toUpperCase().replace("-", "_"); + String serviceName = "SP_SERVICE__" + normalizedProxyId + "__" + containerIndex; + + // Ensure it doesn't exceed Snowflake identifier length of 255 chars + if (serviceName.length() > 255) { + serviceName = serviceName.substring(0, 255); + } + return serviceName; + } + + private String buildServiceSpecYaml(ContainerSpec spec, Map env, SpcsSpecExtension specExtension, Proxy proxy, String serviceName, Authentication authentication) { + StringBuilder yaml = new StringBuilder(); + yaml.append("spec:\n"); + yaml.append(" containers:\n"); + yaml.append(" - name: ").append(quoteYamlValue(spec.getResourceName().getValueOrDefault("container"))).append("\n"); + + // Image from Snowflake image repository + // Format should be: ////: + // If image contains snowflakecomputing.com domain, remove it and convert to the correct format + String image = spec.getImage().getValue(); + image = formatSnowflakeImageName(image); + yaml.append(" image: ").append(quoteYamlValue(image)).append("\n"); + + // Command + if (spec.getCmd().isPresent() && !spec.getCmd().getValue().isEmpty()) { + yaml.append(" command:\n"); + for (String cmd : spec.getCmd().getValue()) { + yaml.append(" - ").append(quoteYamlValue(cmd)).append("\n"); + } + } + + // Environment variables (must be a map, not a list) + if (!env.isEmpty()) { + yaml.append(" env:\n"); + for (Map.Entry entry : env.entrySet()) { + yaml.append(" ").append(quoteYamlValue(entry.getKey())).append(": ").append(quoteYamlValue(entry.getValue())).append("\n"); + } + } + + // Resources (memory and CPU) + yaml.append(" resources:\n"); + boolean hasRequests = false; + if (spec.getMemoryRequest().isPresent()) { + yaml.append(" requests:\n"); + hasRequests = true; + String memoryValue = formatMemoryValue(spec.getMemoryRequest().getValue()); + yaml.append(" memory: ").append(memoryValue).append("\n"); + } + if (spec.getCpuRequest().isPresent()) { + if (!hasRequests) { + yaml.append(" requests:\n"); + } + String cpuValue = formatCpuValue(spec.getCpuRequest().getValue()); + yaml.append(" cpu: ").append(cpuValue).append("\n"); + } + + // Ports/endpoints (at containers level) + // Endpoints are always needed (even when running inside SPCS) for internal DNS to be available + List endpointNames = new ArrayList<>(); + if (spec.getPortMapping() != null && !spec.getPortMapping().isEmpty()) { + yaml.append(" endpoints:\n"); + for (eu.openanalytics.containerproxy.model.spec.PortMapping portMapping : spec.getPortMapping()) { + String endpointName = portMapping.getName(); + endpointNames.add(endpointName); + yaml.append(" - name: ").append(quoteYamlValue(endpointName)).append("\n"); + yaml.append(" port: ").append(portMapping.getPort()).append("\n"); + yaml.append(" protocol: HTTP\n"); // Public endpoints only support HTTP + // Set public access: true when running external to SPCS, false when running inside SPCS (internal DNS is used) + yaml.append(" public: ").append(!isRunningInsideSpcs()).append("\n"); + } + } + + // Capabilities (at root level, same as spec) + // Set executeAsCaller: true only if SPCS user token is available (indicates caller's rights context) + yaml.append("capabilities:\n"); + yaml.append(" securityContext:\n"); + boolean executeAsCaller = false; + if (authentication instanceof SpcsAuthenticationToken) { + Object credentials = authentication.getCredentials(); + if (credentials != null) { + String userToken = credentials.toString(); + if (!userToken.isBlank()) { + executeAsCaller = true; + } + } + } + yaml.append(" executeAsCaller: ").append(executeAsCaller).append("\n"); + + // Service roles (at root level, same as spec) + // Service roles are always needed (even when running inside SPCS) when endpoints are present + if (!endpointNames.isEmpty()) { + yaml.append("serviceRoles:\n"); + yaml.append("- name: ").append(quoteYamlValue(serviceName)).append("\n"); + yaml.append(" endpoints:\n"); + for (String endpointName : endpointNames) { + yaml.append(" - ").append(quoteYamlValue(endpointName)).append("\n"); + } + } + + return yaml.toString(); + } + + /** + * Formats a Snowflake image name to the correct format. + * If the image contains a snowflakecomputing.com domain, removes it and extracts the path. + * Expected format: ////: + * + * @param image The image name (e.g., "org-account.registry.snowflakecomputing.com/path/to/image:tag" or "/path/to/image:tag") + * @return Formatted image name with domain removed (e.g., "/path/to/image:tag") + */ + private String formatSnowflakeImageName(String image) { + if (image == null || image.isEmpty()) { + return image; + } + + // If image contains snowflakecomputing.com, extract the path part after the domain + if (image.contains("snowflakecomputing.com")) { + // Find the path part after the domain (look for / after snowflakecomputing.com) + int domainIndex = image.indexOf("snowflakecomputing.com"); + int pathStart = image.indexOf('/', domainIndex); + if (pathStart >= 0) { + // Extract path starting from / + return image.substring(pathStart); + } + // If no / found after domain, return as-is (unlikely but handle gracefully) + return image; + } + + // If image already starts with /, it's already in the correct format + // Otherwise, return as-is (might be a different format) + return image; + } + + /** + * Formats a memory value for Snowflake SPCS. + * If the value already has a unit (g, gi, m, mi, t, ti), returns it as-is. + * Otherwise, assumes the value is in megabytes and converts to appropriate unit. + * + * Supported units: g, gi, m, mi, t, ti (Snowflake accepts capitalized forms like Gi, Mi) + * Converts large values to larger units (e.g., 2048m -> 2Gi, 1024m -> 1Gi) + * + * @param memoryValue The memory value (e.g., "2048" or "2Gi") + * @return Formatted memory value with capitalized unit (e.g., "2Gi" or "512Mi") + */ + private String formatMemoryValue(String memoryValue) { + if (memoryValue == null || memoryValue.isEmpty()) { + return memoryValue; + } + // Check if value already has a supported unit (case-insensitive) + // Supported units per Snowflake docs: M, Mi, G, Gi (uppercase first letter required) + String lowerValue = memoryValue.toLowerCase(); + if (lowerValue.matches(".*(m|mi|g|gi)$")) { + // Already has a unit, normalize to uppercase first letter + // Extract the numeric part and unit + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^(\\d+(?:\\.\\d+)?)([mM][iI]?|[gG][iI]?)$"); + java.util.regex.Matcher matcher = pattern.matcher(memoryValue); + if (matcher.matches()) { + String numberPart = matcher.group(1); + String unitPart = matcher.group(2).toLowerCase(); + // Normalize unit: m -> M, mi -> Mi, g -> G, gi -> Gi + String normalizedUnit; + if (unitPart.equals("m")) { + normalizedUnit = "M"; + } else if (unitPart.equals("mi")) { + normalizedUnit = "Mi"; + } else if (unitPart.equals("g")) { + normalizedUnit = "G"; + } else if (unitPart.equals("gi")) { + normalizedUnit = "Gi"; + } else { + normalizedUnit = unitPart; // Should not happen + } + return numberPart + normalizedUnit; + } + // If regex doesn't match, return as-is (shouldn't happen) + return memoryValue; + } + + // Parse the numeric value + try { + double value = Double.parseDouble(memoryValue); + + // Convert megabytes to appropriate unit with capitalized format + // 1024 MB = 1 GiB, 1000 MB = 1 GB + // Use binary units (Gi, Mi) for consistency with Kubernetes conventions + if (value >= 1024) { + // Convert to GiB (gibibytes) + double gib = value / 1024; + // Format to remove unnecessary decimals + if (gib == Math.floor(gib)) { + return String.valueOf((long) gib) + "Gi"; + } else { + // Round to 2 decimal places for large values + return String.format("%.2fGi", gib).replaceAll("\\.?0+$", ""); + } + } else { + // Use MiB (mebibytes) for values < 1024 MB + return (long) value + "Mi"; + } + } catch (NumberFormatException e) { + // If parsing fails, just append "Mi" as fallback + return memoryValue + "Mi"; + } + } + + /** + * Formats a CPU value for Snowflake SPCS. + * CPU can be specified as: + * - Millicores with "m" suffix (e.g., "500m", "1000m") - returned as-is + * According to Snowflake docs, fractional CPUs can be expressed as "m" (e.g., 500m = 0.5 CPUs) + * - Fractional CPUs directly (e.g., "0.5", "1", "2.5") - returned as-is + * - Whole numbers >= 1 without unit - treated as millicores and converted to fractional CPUs + * (e.g., "256" -> "0.256", "1000" -> "1", "1500" -> "1.5") + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/specification-reference#containers-resources-field + * + * @param cpuValue The CPU value (e.g., "256", "1000", "0.5", "500m", or "1000m") + * @return Formatted CPU value (e.g., "0.256", "1", "0.5", "500m", or "1000m") + */ + private String formatCpuValue(String cpuValue) { + if (cpuValue == null || cpuValue.isEmpty()) { + return cpuValue; + } + // Check if value already has "m" unit (millicores) + String lowerValue = cpuValue.toLowerCase(); + if (lowerValue.endsWith("m")) { + // Already has millicore unit, return as-is (Snowflake accepts "m" suffix for fractional CPUs) + return cpuValue; + } + + // Parse the numeric value + try { + double value = Double.parseDouble(cpuValue); + + // If value < 1, assume it's already in fractional CPU format (e.g., 0.5) + if (value < 1.0) { + return cpuValue; + } + + // Value >= 1, assume it's in millicores and convert to fractional CPUs + // (e.g., 256 millicores = 0.256 CPUs, 1000 millicores = 1 CPU) + double cpus = value / 1000.0; + // Format to remove unnecessary decimals + if (cpus == Math.floor(cpus)) { + return String.valueOf((long) cpus); + } else { + // Round to 3 decimal places and remove trailing zeros + return String.format("%.3f", cpus).replaceAll("\\.?0+$", ""); + } + } catch (NumberFormatException e) { + // If parsing fails, return as-is + return cpuValue; + } + } + + /** + * Safely quotes a YAML string value to prevent injection attacks. + * Escapes special characters and wraps in double quotes when necessary. + */ + private String quoteYamlValue(String value) { + if (value == null) { + return "\"\""; + } + + // Always quote values that could be interpreted as YAML syntax + // Check for special YAML characters, control characters, or values that look like YAML types + boolean needsQuoting = value.contains(":") + || value.contains("#") + || value.contains("@") + || value.contains("&") + || value.contains("*") + || value.contains("!") + || value.contains("|") + || value.contains(">") + || value.contains("'") + || value.contains("\"") + || value.contains("\n") + || value.contains("\r") + || value.contains("\t") + || value.contains("{{") // Template syntax + || value.contains("}}") + || value.trim().isEmpty() // Empty strings + || value.matches("^(true|false|null|yes|no|on|off)$") // YAML boolean/null keywords + || value.matches("^-?\\d+$") // Numbers at start of line + || value.startsWith("-") // List indicator + || value.startsWith("[") // Array syntax + || value.startsWith("{"); // Object syntax + + if (needsQuoting) { + // Escape backslashes first, then quotes + String escaped = value + .replace("\\", "\\\\") // Escape backslashes + .replace("\"", "\\\"") // Escape double quotes + .replace("\n", "\\n") // Escape newlines + .replace("\r", "\\r") // Escape carriage returns + .replace("\t", "\\t"); // Escape tabs + return "\"" + escaped + "\""; + } + + return value; + } + + @Override + protected void doStopProxy(Proxy proxy) { + if (Thread.currentThread().isInterrupted()) { + return; + } + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName != null) { + // Parse full service name: database.schema.service + String[] parts = fullServiceName.split("\\."); + if (parts.length == 3) { + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + try { + snowflakeServiceAPI.deleteService(serviceDb, serviceSchema, serviceName, true); + slog.info(proxy, String.format("Deleted Snowflake service: %s", fullServiceName)); + } catch (ApiException e) { + slog.warn(proxy, String.format("Error deleting Snowflake service %s: %s", fullServiceName, e.getMessage())); + } + } + } + } + + // Wait for service to be stopped + boolean isInactive = Retrying.retry((currentAttempt, maxAttempts) -> { + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName != null) { + String[] parts = fullServiceName.split("\\."); + if (parts.length == 3) { + try { + List containers = snowflakeServiceAPI.listServiceContainers(parts[0], parts[1], parts[2]); + // If we can list containers, service is not fully stopped + if (containers != null && !containers.isEmpty()) { + // Check if containers are stopped/suspended + boolean allStopped = true; + for (ServiceContainer serviceContainer : containers) { + String status = serviceContainer.getStatus(); + String serviceStatus = serviceContainer.getServiceStatus(); + if (status != null && !status.equals("SUSPENDED") && !status.equals("STOPPED") && !status.equals("DELETED")) { + allStopped = false; + break; + } + if (serviceStatus != null && !serviceStatus.equals("SUSPENDED") && !serviceStatus.equals("STOPPED") && !serviceStatus.equals("DELETED")) { + allStopped = false; + break; + } + } + if (!allStopped) { + return Retrying.FAILURE; + } + } + } catch (ApiException e) { + // Service might be deleted already + if (e.getCode() == 404) { + return Retrying.SUCCESS; + } + } + } + } + } + return Retrying.SUCCESS; + }, serviceWaitTime, "Stopping SPCS Service", 0, proxy, slog); + + if (!isInactive) { + slog.warn(proxy, "Service did not get into stopping state"); + } + } + + @Override + public void stopProxies(Collection proxies) { + for (Proxy proxy : proxies) { + try { + stopProxy(proxy); + } catch (Exception e) { + log.error("Error stopping proxy", e); + } + } + } + + @Override + protected String getPropertyPrefix() { + return PROPERTY_PREFIX; + } + + @Override + public List scanExistingContainers() { + log.info("Scanning for existing SPCS services to recover in database schema {}.{}", database, schema); + ArrayList containers = new ArrayList<>(); + + try { + // List services starting with "SP_SERVICE_" (uppercase for consistency with Snowflake) + List services = snowflakeServiceAPI.listServices(database, schema, "SP_SERVICE__%", null, null, null); + + if (services == null || services.isEmpty()) { + log.info("No existing SPCS services found to recover"); + return containers; + } + + log.info("Found {} SPCS service(s) to scan for recovery", services.size()); + + for (Service service : services) { + String serviceName = service.getName(); + // Service names are always uppercase, check for "SP_SERVICE_" prefix + if (serviceName == null || !serviceName.startsWith("SP_SERVICE__")) { + continue; + } + + // Check if service has containers and is running, delete if not + if (!checkServiceContainersAndRunningStatus(serviceName)) { + deleteServiceLogReason(serviceName, "Service has no containers or no running containers"); + continue; + } + + // Fetch service and extract all metadata (image, comment metadata, proxyId, containerIndex) + Map metadata = new HashMap<>(); + + if (!fetchServiceImageAndMetadata(serviceName, metadata)) { + deleteServiceLogReason(serviceName, "Error fetching service metadata"); + continue; + } + + // Validate and delete if unrecoverable (uses comment metadata as primary source) + if (!validateAndDeleteIfUnrecoverable(serviceName, metadata)) { + continue; // Service was deleted + } + + // Build and add to recovery list (all data comes from comment metadata) + ExistingContainerInfo containerInfo = buildExistingContainerInfo(serviceName, metadata); + containers.add(containerInfo); + String recoveredUserId = metadata.get(UserIdKey.inst.getKeyAsLabel()); + String recoveredProxyId = metadata.get(ProxyIdKey.inst.getKeyAsLabel()); + String recoveredSpecId = metadata.get(ProxySpecIdKey.inst.getKeyAsLabel()); + log.info("Added service {} to recovery list (userId: {}, proxyId: {}, specId: {})", + serviceName, recoveredUserId, recoveredProxyId, recoveredSpecId); + } + + log.info("Completed scanning SPCS services: {} recoverable service(s) found", containers.size()); + } catch (ApiException e) { + log.error("Error listing services for scan: {}", e.getMessage(), e); + } + + return containers; + } + + /** + * Deletes a service with error handling and logging. + */ + private void deleteServiceLogReason(String serviceName, String reason) { + log.warn("Deleting service {} due to: {}", serviceName, reason); + try { + snowflakeServiceAPI.deleteService(database, schema, serviceName, true); + log.info("Deleted Snowflake service: {}.{}.{}", database, schema, serviceName); + } catch (ApiException e) { + log.warn("Error deleting Snowflake service {}.{}.{}: {}", database, schema, serviceName, e.getMessage()); + } + } + + /** + * Checks if service has containers and if any are running. Returns false if service should be deleted or on error. + * Does not delete the service - caller is responsible for deletion. + */ + private boolean checkServiceContainersAndRunningStatus(String serviceName) { + try { + List serviceContainers = snowflakeServiceAPI.listServiceContainers(database, schema, serviceName); + if (serviceContainers == null || serviceContainers.isEmpty()) { + log.warn("Service {} has no containers", serviceName); + return false; + } + + // Check if any container is running/ready + boolean hasRunningContainer = false; + for (ServiceContainer serviceContainer : serviceContainers) { + String status = serviceContainer.getStatus(); + String serviceStatus = serviceContainer.getServiceStatus(); + if ((status != null && (status.equals("RUNNING") || status.equals("UP") || status.equals("READY"))) || + (serviceStatus != null && (serviceStatus.equals("RUNNING") || serviceStatus.equals("UP") || serviceStatus.equals("READY")))) { + hasRunningContainer = true; + break; + } + } + + if (!hasRunningContainer) { + log.warn("Service {} has no running containers", serviceName); + return false; + } + + return true; + } catch (ApiException e) { + log.warn("Error checking service containers for {}: {}", serviceName, e.getMessage()); + return false; + } + } + + /** + * Also calculates and stores Authorization header for SPCS ingress access + * Adds image, comment metadata, and endpoint URL to the metadata map. + * @param serviceName The service name to fetch + * @param metadata Map to populate with service metadata (will also contain "endpointUrl" key) + * @return true if successful, false on error + */ + private boolean fetchServiceImageAndMetadata(String serviceName, Map metadata) { + try { + // Get the Service object - polymorphic deserialization is now handled correctly by CustomTypeAdapterFactory + Service fullService = snowflakeServiceAPI.fetchService(database, schema, serviceName); + ServiceSpec serviceSpec = fullService.getSpec(); + + // Extract spec_text (YAML string) from the properly deserialized ServiceSpecInlineText + String specText = null; + if (serviceSpec instanceof ServiceSpecInlineText) { + specText = ((ServiceSpecInlineText) serviceSpec).getSpecText(); + } + + // Extract comment (metadata) + // Comment contains all runtime values stored during service creation (similar to Docker labels) + String comment = fullService.getComment(); + if (comment != null && !comment.isEmpty()) { + try { + TypeToken> typeToken = new TypeToken>() {}; + Map commentMetadata = JSON.getGson().fromJson(comment, typeToken.getType()); + if (commentMetadata != null) { + metadata.putAll(commentMetadata); + log.debug("Extracted {} metadata entries from comment for service {}", commentMetadata.size(), serviceName); + } + } catch (Exception e) { + log.warn("Error parsing metadata from comment for service {}: {}", serviceName, e.getMessage()); + } + } + + if (specText != null && !specText.isEmpty()) { + String image = extractImageFromSpecText(specText); + if (image != null && !image.isEmpty()) { + metadata.put("image", image); + } else { + log.warn("Failed to extract image from service spec for service {} (specText length: {})", serviceName, specText.length()); + } + } else { + log.warn("Service spec text is null or empty for service {}", serviceName); + } + + return true; + } catch (ApiException e) { + log.warn("Error fetching service spec for {}: {}", serviceName, e.getMessage()); + return false; + } + } + + /** + * Extracts image name from YAML spec text. + * Expected YAML structure: + * spec: + * containers: + * - name: + * image: + */ + private String extractImageFromSpecText(String specText) { + if (specText == null || specText.isEmpty()) { + log.warn("extractImageFromSpecText: specText is null or empty"); + return null; + } + + String[] lines = specText.split("\n"); + boolean inContainersSection = false; + + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + String trimmed = line.trim(); + + if (trimmed.isEmpty()) { + continue; + } + + // Detect containers section + if (trimmed.equals("containers:") || trimmed.startsWith("containers:")) { + inContainersSection = true; + continue; + } + + // If we're in containers section, look for the image field + if (inContainersSection) { + // Check if we've left the containers section (hit a top-level key at same or less indentation as "containers:") + int leadingSpaces = line.length() - line.trim().length(); + if (leadingSpaces <= 2 && !trimmed.startsWith("-") && + !trimmed.startsWith("name:") && !trimmed.startsWith("image:") && + !trimmed.startsWith("command:") && !trimmed.startsWith("env:") && + !trimmed.startsWith("resources:")) { + // We've left the containers section + break; + } + + // Look for image: field (should be at 4 spaces indentation, after "- name:") + if (trimmed.startsWith("image:")) { + String image = trimmed.substring(6).trim(); + if (image.isEmpty()) { + log.warn("extractImageFromSpecText: found 'image:' but value is empty at line {}", i + 1); + continue; + } + + // Remove quotes if present + if ((image.startsWith("\"") && image.endsWith("\"")) || + (image.startsWith("'") && image.endsWith("'"))) { + image = image.substring(1, image.length() - 1); + } + + log.debug("extractImageFromSpecText: extracted image '{}' from line {}", image, i + 1); + return image; + } + } + } + + log.warn("extractImageFromSpecText: could not find 'image:' field in spec text ({} lines, inContainersSection={})", + lines.length, inContainersSection); + return null; + } + + /** + * Validates service metadata and deletes service if unrecoverable. Returns false if service was deleted. + * Uses comment metadata as primary source (label keys like "openanalytics.eu/sp-proxy-id"). + */ + private boolean validateAndDeleteIfUnrecoverable(String serviceName, Map metadata) { + // Get values from comment metadata using label keys + String instanceId = metadata.get(InstanceIdKey.inst.getKeyAsLabel()); + + // Check realm-id validation + // If current instance has realm-id configured but service doesn't, delete it (orphaned from before realm-id was used) + // If both have realm-id but they don't match, skip it (belongs to another ShinyProxy instance) + String storedRealmId = metadata.get(RealmIdKey.inst.getKeyAsLabel()); + String currentRealmId = identifierService.realmId; + if (currentRealmId != null && storedRealmId == null) { + // Current instance uses realm-id but service doesn't have it - delete orphaned service + deleteServiceLogReason(serviceName, "Missing realm-id"); + return false; + } + if (storedRealmId != null && currentRealmId != null && !storedRealmId.equals(currentRealmId)) { + // Both have realm-id but they don't match - skip it (belongs to another instance) + log.debug("Skipping service {} because realm-id mismatch (stored: {}, current: {})", + serviceName, storedRealmId, currentRealmId); + return false; + } + + // Check if we can recover this proxy based on instanceId + // This ensures we only recover containers started with the current config (unless recover-running-proxies-from-different-config is enabled) + if (!appRecoveryService.canRecoverProxy(instanceId)) { + deleteServiceLogReason(serviceName, String.format("InstanceId mismatch (stored: %s, current: %s)", + instanceId, identifierService.instanceId)); + return false; + } + + return true; + } + + /** + * Parses service comment JSON to extract runtime values (similar to Docker's parseLabelsAsRuntimeValues). + * This automatically extracts all runtime values that were stored in the comment during service creation. + * + * @param serviceName The service name (for logging) + * @param commentMetadata Map of label keys to string values from the service comment JSON + * @return Map of RuntimeValueKey to RuntimeValue, or null if parsing failed + */ + private Map, RuntimeValue> parseCommentAsRuntimeValues(String serviceName, Map commentMetadata) { + if (commentMetadata == null || commentMetadata.isEmpty()) { + log.warn("Comment metadata is null or empty for service {}", serviceName); + return new HashMap<>(); + } + + Map, RuntimeValue> runtimeValues = new HashMap<>(); + + for (RuntimeValueKey key : RuntimeValueKeyRegistry.getRuntimeValueKeys()) { + if (key.getIncludeAsLabel() || key.getIncludeAsAnnotation()) { + String value = commentMetadata.get(key.getKeyAsLabel()); + if (value != null) { + try { + runtimeValues.put(key, new RuntimeValue(key, key.deserializeFromString(value))); + } catch (Exception e) { + log.warn("Error deserializing runtime value {} for service {}: {}", key.getKeyAsLabel(), serviceName, e.getMessage()); + } + } else if (key.isRequired()) { + // value is null but is required - this might be a problem, but don't fail here + // Some required values might come from other sources (service name, service properties, etc.) + log.debug("Required runtime value {} not found in comment for service {}", key.getKeyAsLabel(), serviceName); + } + } + } + + return runtimeValues; + } + + /** + * Builds ExistingContainerInfo from metadata map containing all extracted service data. + * Uses parseCommentAsRuntimeValues to automatically extract runtime values from comment (similar to Docker labels). + */ + private ExistingContainerInfo buildExistingContainerInfo(String serviceName, Map metadata) { + // Full service name: database.schema.serviceName + String fullServiceName = database + "." + schema + "." + serviceName; + + // Extract values needed for validation/special handling + String image = metadata.get("image"); + + + // Parse runtime values from comment metadata (similar to Docker labels) + // This automatically extracts all runtime values that were stored in the comment + Map, RuntimeValue> runtimeValues = parseCommentAsRuntimeValues(serviceName, metadata); + + // Add/override special values that can't be stored in comment (they have includeAsLabel/includeAsAnnotation=false): + + // 1. BackendContainerName - full service name (not stored in comment, derived from service name) + // BackendContainerNameKey has includeAsLabel=false, so it must be set manually (same as Docker backend does) + runtimeValues.put(BackendContainerNameKey.inst, new RuntimeValue(BackendContainerNameKey.inst, new BackendContainerName(fullServiceName))); + + // 2. ContainerImageKey - extracted from service spec (not stored in comment - has includeAsLabel=false) + // Always add ContainerImageKey (required by ShinyProxy AdminController) + if (image == null || image.isEmpty()) { + log.warn("Image not found for service {}, using empty string for ContainerImageKey", serviceName); + image = ""; + } + runtimeValues.put(ContainerImageKey.inst, new RuntimeValue(ContainerImageKey.inst, image)); + + // 3. Add Authorization header to HttpHeaders + // Extract endpoint URL for authorization header (needed for keypair auth token exchange scope) + String endpointUrl = extractEndpointUrlFromService(serviceName); + if (endpointUrl != null) { + HttpHeaders existingHeaders = null; + RuntimeValue existingHeadersValue = runtimeValues.get(HttpHeadersKey.inst); + if (existingHeadersValue != null) { + existingHeaders = existingHeadersValue.getObject(); + } + Map headers = existingHeaders != null ? + new HashMap<>(existingHeaders.jsonValue()) : new HashMap<>(); + + // Get the ingress authorization header + String authorizationHeader = getIngressAuthorization(endpointUrl); + if (authorizationHeader != null && !authorizationHeader.isEmpty()) { + headers.put("Authorization", authorizationHeader); + log.debug("Added Authorization header for recovered SPCS service {} (auth method: {})", serviceName, authMethod); + } else if (authMethod == AuthMethod.KEYPAIR) { + log.warn("Ingress authorization header not available for recovered SPCS service {} (endpoint URL: {})", serviceName, endpointUrl); + } + + // Note: Sf-Context-Current-User-Token header is not available during recovery + // as we don't have access to the Authentication context. + // TODO: It will be added dynamically per request + + runtimeValues.put(HttpHeadersKey.inst, new RuntimeValue(HttpHeadersKey.inst, new HttpHeaders(headers))); + } + + // Empty port bindings (SPCS uses endpoints instead of Docker-style port bindings) + // Ports are exposed via SPCS service endpoints, not mapped to host ports + Map portBindings = new HashMap<>(); + + return new ExistingContainerInfo(serviceName, runtimeValues, image, portBindings); + } + + @Override + public boolean isProxyHealthy(Proxy proxy) { + for (Container container : proxy.getContainers()) { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName == null) { + slog.warn(proxy, "SPCS container failed: service name not found"); + return false; + } + + String[] parts = fullServiceName.split("\\."); + if (parts.length != 3) { + slog.warn(proxy, "SPCS container failed: invalid service name format"); + return false; + } + + // Extract service name (last part) and reuse checkServiceContainersAndRunningStatus + String serviceName = parts[2]; + if (!checkServiceContainersAndRunningStatus(serviceName)) { + slog.warn(proxy, "SPCS container failed: service unhealthy"); + return false; + } + } + return true; + } + + /** + * Extracts the endpoint URL from target URIs for keypair auth token exchange scope. + * This is used when targets are already available (e.g., during startup). + * + * @param targets The target URIs (may be null or empty) + * @return The endpoint URL (scheme + host) or null if not available + */ + private String extractEndpointUrlFromTargets(Map targets) { + if (authMethod == AuthMethod.KEYPAIR && targets != null && !targets.isEmpty()) { + // Extract endpoint URL from the first target URI (already set to ingress URL by calculateTarget) + URI firstTarget = targets.values().iterator().next(); + if (firstTarget != null && "https".equals(firstTarget.getScheme())) { + // Extract base URL (scheme + host) for the scope + return firstTarget.getScheme() + "://" + firstTarget.getHost(); + } + } + return null; + } + + /** + * Extracts the endpoint URL from a service name by fetching its endpoints. + * Uses the same logic as calculateTarget to find the first public endpoint's ingress URL. + * This is used during recovery when we need the endpoint URL but don't have targets yet. + * + * @param serviceName The service name (short name, not fully qualified) + * @return The endpoint URL (scheme + host) or null if not available + */ + private String extractEndpointUrlFromService(String serviceName) { + + try { + // Fetch endpoints (same as calculateTarget does) + List endpoints = snowflakeServiceAPI.showServiceEndpoints(database, schema, serviceName); + if (endpoints != null && !endpoints.isEmpty()) { + // Find the first public HTTP endpoint (same logic as calculateTarget) + for (ServiceEndpoint endpoint : endpoints) { + if (endpoint.getIsPublic() != null && endpoint.getIsPublic() && + endpoint.getIngressUrl() != null && !endpoint.getIngressUrl().isEmpty() && + "HTTP".equalsIgnoreCase(endpoint.getProtocol())) { + String ingressUrl = endpoint.getIngressUrl(); + + // Ingress URL format is typically: https://{endpoint}.snowflakecomputing.com + // Extract base URL (scheme + host) for the scope + if (!ingressUrl.startsWith("https://") && !ingressUrl.startsWith("http://")) { + ingressUrl = "https://" + ingressUrl; + } + + try { + URI uri = new URI(ingressUrl); + return uri.getScheme() + "://" + uri.getHost(); + } catch (java.net.URISyntaxException e) { + log.debug("Invalid ingress URL format for endpoint: {}", ingressUrl); + } + break; + } + } + } + } catch (ApiException e) { + log.debug("Could not fetch endpoints to get endpoint URL for keypair auth: {}", e.getMessage()); + } + + return null; + } + + /** + * Sets up HTTP headers for proxy container communication. + * Sets Authorization header only when running external to SPCS (for ingress access). + * Adds SPCS user context headers when authenticated via SPCS. + * + * @param proxy The proxy (used to get existing headers and container info) + * @param endpointUrl Optional endpoint URL for keypair auth token exchange scope (only used when external) + * @param authentication The authentication object (may be null, used to extract SPCS user token) + * @return Map of merged headers + */ + private Map setupProxyContainerHTTPHeaders(Proxy proxy, String endpointUrl, Authentication authentication) { + // Get existing headers from proxy and merge with new headers + HttpHeaders existingHeaders = proxy.getRuntimeObject(HttpHeadersKey.inst); + Map mergedHeaders = existingHeaders != null ? + new HashMap<>(existingHeaders.jsonValue()) : new HashMap<>(); + + // Set Authorization header only when running external to SPCS (needed for ingress access) + if (!isRunningInsideSpcs()) { + String authorizationHeader = getIngressAuthorization(endpointUrl); + + if (authorizationHeader != null && !authorizationHeader.isEmpty()) { + mergedHeaders.put("Authorization", authorizationHeader); + log.info("Setting up Authorization header for SPCS ingress access (auth method: {})", authMethod); + } else if (authMethod == AuthMethod.KEYPAIR && endpointUrl != null) { + log.warn("Ingress authorization header not available for SPCS access (endpoint URL: {})", endpointUrl); + } + } + + // Add SPCS user headers if authenticated via SPCS + // These headers are forwarded to proxy containers so they can use the caller's identity + // Username header is always added when SPCS authenticated; token header only if available + if (authentication instanceof SpcsAuthenticationToken) { + // Add username header (always present when SPCS authenticated) + Object principal = authentication.getPrincipal(); + if (principal != null) { + String username = principal.toString(); + if (!username.isBlank()) { + mergedHeaders.put("Sf-Context-Current-User", username); + log.debug("Added Sf-Context-Current-User to proxy HttpHeaders"); + } + } + + // Add user token header (only present when executeAsCaller=true on parent service) + Object credentials = authentication.getCredentials(); + if (credentials != null) { + String userToken = credentials.toString(); + if (!userToken.isBlank()) { + mergedHeaders.put("Sf-Context-Current-User-Token", userToken); + log.debug("Added Sf-Context-Current-User-Token to proxy HttpHeaders"); + } + } + } + + return mergedHeaders; + } + + protected URI calculateTarget(Container container, PortMappings.PortMappingEntry portMapping, Integer hostPort) throws Exception { + String fullServiceName = container.getRuntimeValue(BackendContainerNameKey.inst); + if (fullServiceName == null) { + throw new ContainerFailedToStartException("Service name not found while calculating target", null, container); + } + + // database.schema.service name + String[] parts = fullServiceName.split("\\."); + if (parts.length != 3) { + throw new ContainerFailedToStartException("Invalid service name format: " + fullServiceName, null, container); + } + + // Fetch service to get DNS name or ingress URL + try { + Service service = snowflakeServiceAPI.fetchService(parts[0], parts[1], parts[2]); + + if (isRunningInsideSpcs()) { + // When running inside SPCS: use internal DNS name for communication + // The DNS name format is: service-name.unique-id.svc.spcs.internal + String serviceDnsName = service.getDnsName(); + if (serviceDnsName == null || serviceDnsName.isEmpty()) { + throw new ContainerFailedToStartException("Service DNS name not available from REST API", null, container); + } + + log.info("Proxy container DNS name: {}", serviceDnsName); + + int targetPort = portMapping.getPort(); + return new URI(String.format("%s://%s:%s%s", getDefaultTargetProtocol(), serviceDnsName, targetPort, portMapping.getTargetPath())); + } else { + // When running external to SPCS: use ingress URL (HTTPS) for communication + // Note: Public endpoints have protocol HTTP, but ingress URLs use HTTPS scheme + // Need to get the ingress URL from public service endpoints that match the port + List endpoints = snowflakeServiceAPI.showServiceEndpoints(parts[0], parts[1], parts[2]); + int targetPort = portMapping.getPort(); + + // Find public endpoint matching the port (when running external, we need public access) + // Public endpoints have protocol HTTP (not HTTPS), but ingress URLs use HTTPS + ServiceEndpoint matchingEndpoint = null; + for (ServiceEndpoint endpoint : endpoints) { + if (endpoint.getPort() != null && endpoint.getPort().equals(targetPort) && + endpoint.getIsPublic() != null && endpoint.getIsPublic() && + "HTTP".equalsIgnoreCase(endpoint.getProtocol())) { + matchingEndpoint = endpoint; + break; + } + } + + if (matchingEndpoint == null) { + throw new ContainerFailedToStartException("No public HTTP endpoint found for port " + targetPort + " in service " + fullServiceName, null, container); + } + + // Get ingress URL (should already be ready since we wait for endpoints during startup) + String ingressUrl = matchingEndpoint.getIngressUrl(); + if (ingressUrl == null || ingressUrl.isEmpty()) { + throw new ContainerFailedToStartException("Ingress URL not available for port " + targetPort + " in service " + fullServiceName, null, container); + } + + // Check if endpoint is still provisioning (should not happen, but validate anyway) + String lowerUrl = ingressUrl.toLowerCase(); + if (lowerUrl.contains("provisioning") || lowerUrl.contains("progress")) { + throw new ContainerFailedToStartException("Endpoint for port " + targetPort + " in service " + fullServiceName + " is still provisioning: " + ingressUrl, null, container); + } + + // Ingress URL format is typically: https://{endpoint}.snowflakecomputing.com + // Ensure it starts with https:// + if (!ingressUrl.startsWith("https://") && !ingressUrl.startsWith("http://")) { + ingressUrl = "https://" + ingressUrl; + } + + // Validate and create URI + try { + // Append the target path if specified + URI uri = new URI(ingressUrl + (portMapping.getTargetPath() != null ? portMapping.getTargetPath() : "")); + return uri; + } catch (java.net.URISyntaxException e) { + throw new ContainerFailedToStartException("Invalid ingress URL format for port " + targetPort + ": " + ingressUrl, e, container); + } + } + } catch (ApiException e) { + throw new ContainerFailedToStartException("Failed to fetch service or endpoints: " + e.getMessage(), e, container); + } + } + + /** + * Gets the Authorization header value for use in HTTPS proxy forwarding via ingress. + * When running external to SPCS and forwarding HTTPS requests via ingress, + * this header value should be used for the Authorization header. + * + * For PAT and key-pair tokens: returns "Snowflake Token=\"\"" + * For SPCS session token: returns "Bearer " (token is read from session file) + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowpark-container-services/tutorials/advanced/tutorial-8-access-public-endpoint-programmatically#option-2-send-requests-to-the-service-endpoint-programmatically-by-using-a-jwt + * + * @param endpointUrl Optional endpoint URL for key-pair token exchange scope. + * If null, a basic scope will be used. + * @return The Authorization header value (e.g., "Bearer " or "Snowflake Token=\"\""), or null if not available + */ + public String getIngressAuthorization(String endpointUrl) { + String token; + if (authMethod == AuthMethod.SPCS_SESSION_TOKEN) { + // For SPCS session token: use supplier to get token directly from session file + token = jwtTokenSupplier != null ? jwtTokenSupplier.get() : null; + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } else if (authMethod == AuthMethod.PAT) { + // For PAT: use supplier to get token directly + token = jwtTokenSupplier != null ? jwtTokenSupplier.get() : null; + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } else if (authMethod == AuthMethod.KEYPAIR) { + // For keypair: exchange JWT for Snowflake OAuth token + if (jwtTokenSupplier == null) { + return null; + } + String jwtToken = jwtTokenSupplier.get(); + try { + token = exchangeJwtForSnowflakeToken(jwtToken, endpointUrl); + if (token == null || token.isEmpty()) { + return null; + } + // Format: Snowflake Token="" + return "Snowflake Token=\"" + token + "\""; + } catch (IOException e) { + log.error("Failed to exchange JWT for Snowflake OAuth token for ingress", e); + throw new RuntimeException("Failed to exchange JWT token for ingress authentication: " + e.getMessage(), e); + } + } + throw new IllegalStateException("Unknown authentication method: " + authMethod); + } + + /** + * Gets the username used for authentication. + * + * @return The username, or null if using SPCS session token + */ + public String getUsername() { + return username; + } + + /** + * Gets the authentication method currently being used. + * + * @return The authentication method + */ + public AuthMethod getAuthMethod() { + return authMethod; + } + + /** + * Checks if ShinyProxy is running inside SPCS. + * + * @return true if running inside SPCS, false if running external + */ + public boolean isRunningInsideSpcs() { + return authMethod == AuthMethod.SPCS_SESSION_TOKEN; + } + + + /** + * Generates a JWT token from the RSA private key for keypair authentication. + * The JWT is signed with RS256 algorithm and includes standard Snowflake claims. + * This method is called via supplier to allow automatic regeneration when tokens expire. + * + * JWT Claims: + * - iss: {ACCOUNT}.{USERNAME}.{KEY_SHA256} + * - sub: {ACCOUNT}.{USERNAME} + * - exp: current time + 30 seconds (short-lived token) + * + * @return The JWT token string + */ + private String generateJwtTokenForKeypair() { + try { + // Read RSA private key + PrivateKey privateKey = loadPrivateKey(privateRsaKeyPath); + + // Use stored account identifier (convert hyphens to underscores for JWT claims) + String account = accountIdentifier.replace("-", "_"); + + // Calculate SHA256 of public key for issuer claim + String keySha256 = calculatePublicKeySha256((RSAPrivateKey) privateKey); + + // Build issuer: {ACCOUNT}.{USERNAME}.{KEY_SHA256} + String issuer = account.toUpperCase() + "." + username.toUpperCase() + "." + keySha256; + + // Build subject: {ACCOUNT}.{USERNAME} + String subject = account.toUpperCase() + "." + username.toUpperCase(); + + // Expiration: current time + 30 seconds + long now = System.currentTimeMillis() / 1000; // Unix timestamp in seconds + Date expiration = new Date((now + 30) * 1000); + + // Create JWT claims set + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .issuer(issuer) + .subject(subject) + .expirationTime(expiration) + .build(); + + // Create JWS header with RS256 algorithm + JWSHeader header = new JWSHeader(JWSAlgorithm.RS256); + + // Create signed JWT + SignedJWT signedJWT = new SignedJWT(header, claimsSet); + + // Sign the JWT + JWSSigner signer = new RSASSASigner(privateKey); + signedJWT.sign(signer); + + // Serialize to compact form + String jwt = signedJWT.serialize(); + + log.debug("Generated JWT token for keypair authentication (iss: {}, sub: {})", issuer, subject); + return jwt; + + } catch (Exception e) { + log.error("Error generating JWT token for keypair authentication", e); + throw new RuntimeException("Failed to generate JWT token: " + e.getMessage(), e); + } + } + + /** + * Loads an RSA private key from a file path. + * Supports both PKCS#8 (-----BEGIN PRIVATE KEY-----) and PKCS#1 (-----BEGIN RSA PRIVATE KEY-----) formats. + * + * @param keyPath Path to the private key file + * @return The PrivateKey object + * @throws Exception If the key cannot be loaded or parsed + */ + private PrivateKey loadPrivateKey(String keyPath) throws Exception { + String keyContent = Files.readString(Paths.get(keyPath)); + + // Remove header, footer, and whitespace + keyContent = keyContent + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----BEGIN RSA PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replace("-----END RSA PRIVATE KEY-----", "") + .replaceAll("\\s", ""); + + byte[] keyBytes = Base64.getDecoder().decode(keyContent); + + try { + // Try PKCS#8 format first (most common) + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + return keyFactory.generatePrivate(keySpec); + } catch (Exception e) { + // If PKCS#8 fails, try PKCS#1 format + // PKCS#1 keys need to be converted to PKCS#8 format + // For simplicity, we'll throw an error suggesting conversion + throw new IllegalArgumentException("Unable to parse RSA private key. Please ensure the key is in PKCS#8 format (-----BEGIN PRIVATE KEY-----). " + + "If you have a PKCS#1 key (-----BEGIN RSA PRIVATE KEY-----), convert it using: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pkcs8.pem", e); + } + } + + /** + * Calculates the SHA256 hash of the RSA public key. + * This is used in the issuer (iss) claim. + * + * For RSA keys, the public key consists of modulus and public exponent. + * The standard public exponent is 65537 (0x10001), which is used for most RSA keys. + * + * @param privateKey The RSA private key + * @return The SHA256 hash as a hexadecimal string (uppercase) + * @throws Exception If the hash cannot be calculated + */ + private String calculatePublicKeySha256(RSAPrivateKey privateKey) throws Exception { + // Use standard RSA public exponent (65537 = 0x10001) + // This is the most common value for RSA keys + java.math.BigInteger publicExponent = new java.math.BigInteger("65537"); + + // Create public key specification using modulus and public exponent + RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(privateKey.getModulus(), publicExponent); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); + + // Get the DER-encoded public key + byte[] publicKeyBytes = publicKey.getEncoded(); + + // Calculate SHA256 hash + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(publicKeyBytes); + + // Convert to hexadecimal string (uppercase) + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString().toUpperCase(); + } + + + /** + * Exchanges a JWT (key-pair) token for a Snowflake OAuth token. + * This is required when forwarding HTTPS requests via ingress with key-pair authentication. + * + * Implementation note: This requires JWT encoding with RS256 algorithm and OAuth token exchange. + * Reference: https://medium.com/@vladimir.timofeenko/hands-on-with-spcs-container-networking-b347866279f9 + * + * @param jwtToken The JWT token to exchange + * @param endpointUrl Optional SPCS endpoint URL for the scope. If null, uses account URL. + * @return The Snowflake OAuth token + * @throws IOException If token exchange fails + */ + private String exchangeJwtForSnowflakeToken(String jwtToken, String endpointUrl) throws IOException { + try { + // Build OAuth token endpoint URL + String oauthTokenUrl = accountUrl + "/oauth/token"; + + // Build scope - format: session:role:{role} {endpointUrl} or just {endpointUrl} + // For now, if endpointUrl is provided, use it; otherwise use account URL + String scope = endpointUrl != null ? endpointUrl : accountUrl; + + // Build form-encoded request body + StringBuilder formData = new StringBuilder(); + formData.append("grant_type=").append(URLEncoder.encode("urn:ietf:params:oauth:grant-type:jwt-bearer", StandardCharsets.UTF_8)); + formData.append("&scope=").append(URLEncoder.encode(scope, StandardCharsets.UTF_8)); + formData.append("&assertion=").append(URLEncoder.encode(jwtToken, StandardCharsets.UTF_8)); + + // Create HTTP request + RequestBody requestBody = RequestBody.create( + formData.toString(), + MediaType.parse("application/x-www-form-urlencoded") + ); + + Request request = new Request.Builder() + .url(oauthTokenUrl) + .post(requestBody) + .header("Content-Type", "application/x-www-form-urlencoded") + .build(); + + // Execute request using OkHttpClient + OkHttpClient httpClient = new OkHttpClient(); + try (Response response = httpClient.newCall(request).execute()) { + if (!response.isSuccessful()) { + String errorBody = response.body() != null ? response.body().string() : "No error body"; + throw new IOException("OAuth token exchange failed with status " + response.code() + ": " + errorBody); + } + + if (response.body() == null) { + throw new IOException("OAuth token exchange returned empty response"); + } + + // Parse JSON response to extract access_token + String responseBody = response.body().string(); + // Format: {"access_token":"...","token_type":"Bearer","expires_in":3600} + try { + com.google.gson.JsonObject jsonResponse = com.google.gson.JsonParser.parseString(responseBody).getAsJsonObject(); + if (!jsonResponse.has("access_token")) { + throw new IOException("OAuth token exchange response does not contain access_token: " + responseBody); + } + String oauthToken = jsonResponse.get("access_token").getAsString(); + log.debug("Successfully exchanged JWT for Snowflake OAuth token (scope: {})", scope); + return oauthToken; + } catch (com.google.gson.JsonSyntaxException e) { + throw new IOException("OAuth token exchange response is not valid JSON: " + responseBody, e); + } + } + } catch (Exception e) { + if (e instanceof IOException) { + throw e; + } + throw new IOException("Error exchanging JWT for Snowflake OAuth token: " + e.getMessage(), e); + } + } + + /** + * Attempts to fetch service logs when a service fails to start. + * This is a best-effort attempt - if it fails, returns null and the error handling will provide SQL instructions instead. + * + * Reference: https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/services/services-introduction + * REST API endpoint: GET /api/v2/databases/{database}/schemas/{schema}/services/{service_name}/logs + * + * @param database Database name + * @param schema Schema name + * @param serviceName Service name + * @return A summary of recent logs (last few lines), or null if logs cannot be fetched + */ + private String fetchServiceLogsForError(String database, String schema, String serviceName) { + try { + // First, try to get container info to get instance and container names + List containers = snowflakeServiceAPI.listServiceContainers(database, schema, serviceName); + if (containers == null || containers.isEmpty()) { + return null; + } + + // Use the first container that has info + ServiceContainer container = containers.get(0); + String instanceIdStr = container.getInstanceId(); + String containerName = container.getContainerName(); + + if (instanceIdStr == null || containerName == null) { + return null; + } + + // Convert instanceId from String to Integer (API expects Integer) + Integer instanceId; + try { + instanceId = Integer.parseInt(instanceIdStr); + } catch (NumberFormatException e) { + log.debug("Invalid instanceId format: {}", instanceIdStr); + return null; + } + + // Use the generated API method to fetch logs + eu.openanalytics.containerproxy.backend.spcs.client.model.FetchServiceLogs200Response response = + snowflakeServiceAPI.fetchServiceLogs(database, schema, serviceName, instanceId, containerName, 50); + + if (response == null || response.getSystem$getServiceLogs() == null) { + return null; + } + + String logContent = response.getSystem$getServiceLogs(); + if (logContent.isEmpty()) { + return null; + } + + // Extract last few lines (limit to avoid huge error messages) + String[] lines = logContent.split("\n"); + int maxLines = 10; + if (lines.length > maxLines) { + StringBuilder summary = new StringBuilder(); + summary.append("(last ").append(maxLines).append(" lines of ").append(lines.length).append(" total)\n"); + for (int i = lines.length - maxLines; i < lines.length; i++) { + summary.append(lines[i]).append("\n"); + } + return summary.toString().trim(); + } + return logContent.trim(); + } catch (ApiException e) { + log.debug("Could not fetch service logs via API: {}", e.getMessage()); + return null; + } catch (Exception e) { + log.debug("Could not fetch service logs for error reporting: {}", e.getMessage()); + return null; + } + } + +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java new file mode 100644 index 00000000..618bacc6 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtension.java @@ -0,0 +1,74 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.model.spec.AbstractSpecExtension; +import eu.openanalytics.containerproxy.model.spec.ISpecExtension; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionContext; +import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; +import eu.openanalytics.containerproxy.spec.expression.SpelField; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@EqualsAndHashCode(callSuper = true) +@Data +@Setter +@Getter +@Builder(toBuilder = true) +@AllArgsConstructor(access = AccessLevel.PRIVATE) // force Spring to not use constructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) // Jackson deserialize compatibility +public class SpcsSpecExtension extends AbstractSpecExtension { + + @Builder.Default + SpelField.String spcsComputePool = new SpelField.String(); + + @Builder.Default + SpelField.String spcsDatabase = new SpelField.String(); + + @Builder.Default + SpelField.String spcsSchema = new SpelField.String(); + + @Builder.Default + SpelField.StringList spcsExternalAccessIntegrations = new SpelField.StringList(); + + @Override + public ISpecExtension firstResolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return toBuilder() + .spcsComputePool(spcsComputePool.resolve(resolver, context)) + .spcsDatabase(spcsDatabase.resolve(resolver, context)) + .spcsSchema(spcsSchema.resolve(resolver, context)) + .spcsExternalAccessIntegrations(spcsExternalAccessIntegrations.resolve(resolver, context)) + .build(); + } + + @Override + public ISpecExtension finalResolve(SpecExpressionResolver resolver, SpecExpressionContext context) { + return this; + } + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java new file mode 100644 index 00000000..0f1b6e77 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/SpcsSpecExtensionProvider.java @@ -0,0 +1,40 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.backend.spcs; + +import eu.openanalytics.containerproxy.spec.ISpecExtensionProvider; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Setter +@Getter +@Configuration +@ConfigurationProperties(prefix = "proxy") +public class SpcsSpecExtensionProvider implements ISpecExtensionProvider { + + private List specs; + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiCallback.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiCallback.java new file mode 100644 index 00000000..7c547800 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiCallback.java @@ -0,0 +1,60 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.Map; +import java.util.List; + +/** + * Callback for asynchronous API call. + * + * @param The return type + */ +public interface ApiCallback { + /** + * This is called when the API call fails. + * + * @param e The exception causing the failure + * @param statusCode Status code of the response if available, otherwise it would be 0 + * @param responseHeaders Headers of the response if available, otherwise it would be null + */ + void onFailure(ApiException e, int statusCode, Map> responseHeaders); + + /** + * This is called when the API call succeeded. + * + * @param result The result deserialized from response + * @param statusCode Status code of the response + * @param responseHeaders Headers of the response + */ + void onSuccess(T result, int statusCode, Map> responseHeaders); + + /** + * This is called when the API upload processing. + * + * @param bytesWritten bytes Written + * @param contentLength content length of request body + * @param done write end + */ + void onUploadProgress(long bytesWritten, long contentLength, boolean done); + + /** + * This is called when the API download processing. + * + * @param bytesRead bytes Read + * @param contentLength content length of the response + * @param done Read end + */ + void onDownloadProgress(long bytesRead, long contentLength, boolean done); +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java new file mode 100644 index 00000000..3d74cda2 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiClient.java @@ -0,0 +1,1708 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import okhttp3.*; +import okhttp3.internal.http.HttpMethod; +import okhttp3.internal.tls.OkHostnameVerifier; +import okhttp3.logging.HttpLoggingInterceptor; +import okhttp3.logging.HttpLoggingInterceptor.Level; +import okio.Buffer; +import okio.BufferedSink; +import okio.Okio; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; + +import javax.net.ssl.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Type; +import java.net.URI; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import eu.openanalytics.containerproxy.backend.spcs.client.auth.Authentication; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBasicAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.ApiKeyAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.OAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.RetryingOAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.OAuthFlow; + +/** + *

ApiClient class.

+ */ +public class ApiClient { + + protected String basePath = "https://org-account.snowflakecomputing.com"; + protected List servers = new ArrayList(Arrays.asList( + new ServerConfiguration( + "https://org-account.snowflakecomputing.com", + "Snowflake Warehouse API", + new HashMap() + ) + )); + protected Integer serverIndex = 0; + protected Map serverVariables = null; + protected boolean debugging = false; + protected Map defaultHeaderMap = new HashMap(); + protected Map defaultCookieMap = new HashMap(); + protected String tempFolderPath = null; + + protected Map authentications; + + protected DateFormat dateFormat; + protected DateFormat datetimeFormat; + protected boolean lenientDatetimeFormat; + protected int dateLength; + + protected InputStream sslCaCert; + protected boolean verifyingSsl; + protected KeyManager[] keyManagers; + + protected OkHttpClient httpClient; + protected JSON json; + + protected HttpLoggingInterceptor loggingInterceptor; + + /** + * Basic constructor for ApiClient + */ + public ApiClient() { + init(); + initHttpClient(); + + // Setup authentications (key: authentication name, value: authentication). + authentications.put("KeyPair", new HttpBearerAuth("bearer")); + authentications.put("ExternalOAuth", new HttpBearerAuth("bearer")); + authentications.put("SnowflakeOAuth", new OAuth()); + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Basic constructor with custom OkHttpClient + * + * @param client a {@link okhttp3.OkHttpClient} object + */ + public ApiClient(OkHttpClient client) { + init(); + + httpClient = client; + + // Setup authentications (key: authentication name, value: authentication). + authentications.put("KeyPair", new HttpBearerAuth("bearer")); + authentications.put("ExternalOAuth", new HttpBearerAuth("bearer")); + authentications.put("SnowflakeOAuth", new OAuth()); + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + /** + * Constructor for ApiClient to support access token retry on 401/403 configured with client ID + * + * @param clientId client ID + */ + public ApiClient(String clientId) { + this(clientId, null, null); + } + + /** + * Constructor for ApiClient to support access token retry on 401/403 configured with client ID and additional parameters + * + * @param clientId client ID + * @param parameters a {@link java.util.Map} of parameters + */ + public ApiClient(String clientId, Map parameters) { + this(clientId, null, parameters); + } + + /** + * Constructor for ApiClient to support access token retry on 401/403 configured with client ID, secret, and additional parameters + * + * @param clientId client ID + * @param clientSecret client secret + * @param parameters a {@link java.util.Map} of parameters + */ + public ApiClient(String clientId, String clientSecret, Map parameters) { + this(null, clientId, clientSecret, parameters); + } + + /** + * Constructor for ApiClient to support access token retry on 401/403 configured with base path, client ID, secret, and additional parameters + * + * @param basePath base path + * @param clientId client ID + * @param clientSecret client secret + * @param parameters a {@link java.util.Map} of parameters + */ + public ApiClient(String basePath, String clientId, String clientSecret, Map parameters) { + init(); + if (basePath != null) { + this.basePath = basePath; + } + + String tokenUrl = ""; + if (!"".equals(tokenUrl) && !URI.create(tokenUrl).isAbsolute()) { + URI uri = URI.create(getBasePath()); + tokenUrl = uri.getScheme() + ":" + + (uri.getAuthority() != null ? "//" + uri.getAuthority() : "") + + tokenUrl; + if (!URI.create(tokenUrl).isAbsolute()) { + throw new IllegalArgumentException("OAuth2 token URL must be an absolute URL"); + } + } + RetryingOAuth retryingOAuth = new RetryingOAuth(tokenUrl, clientId, OAuthFlow.IMPLICIT, clientSecret, parameters); + authentications.put( + "SnowflakeOAuth", + retryingOAuth + ); + initHttpClient(Collections.singletonList(retryingOAuth)); + // Setup authentications (key: authentication name, value: authentication). + authentications.put("KeyPair", new HttpBearerAuth("bearer")); + authentications.put("ExternalOAuth", new HttpBearerAuth("bearer")); + + // Prevent the authentications from being modified. + authentications = Collections.unmodifiableMap(authentications); + } + + protected void initHttpClient() { + initHttpClient(Collections.emptyList()); + } + + protected void initHttpClient(List interceptors) { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.addNetworkInterceptor(getProgressInterceptor()); + for (Interceptor interceptor: interceptors) { + builder.addInterceptor(interceptor); + } + + httpClient = builder.build(); + } + + protected void init() { + verifyingSsl = true; + + json = new JSON(); + + // Set default User-Agent. + setUserAgent("OpenAPI-Generator/0.1.0/java"); + + authentications = new HashMap(); + } + + /** + * Get base path + * + * @return Base path + */ + public String getBasePath() { + return basePath; + } + + /** + * Set base path + * + * @param basePath Base path of the URL (e.g https://org-account.snowflakecomputing.com) + * @return An instance of ApiClient + */ + public ApiClient setBasePath(String basePath) { + this.basePath = basePath; + this.serverIndex = null; + return this; + } + + public List getServers() { + return servers; + } + + public ApiClient setServers(List servers) { + this.servers = servers; + return this; + } + + public Integer getServerIndex() { + return serverIndex; + } + + public ApiClient setServerIndex(Integer serverIndex) { + this.serverIndex = serverIndex; + return this; + } + + public Map getServerVariables() { + return serverVariables; + } + + public ApiClient setServerVariables(Map serverVariables) { + this.serverVariables = serverVariables; + return this; + } + + /** + * Get HTTP client + * + * @return An instance of OkHttpClient + */ + public OkHttpClient getHttpClient() { + return httpClient; + } + + /** + * Set HTTP client, which must never be null. + * + * @param newHttpClient An instance of OkHttpClient + * @return ApiClient + * @throws java.lang.NullPointerException when newHttpClient is null + */ + public ApiClient setHttpClient(OkHttpClient newHttpClient) { + this.httpClient = Objects.requireNonNull(newHttpClient, "HttpClient must not be null!"); + return this; + } + + /** + * Get JSON + * + * @return JSON object + */ + public JSON getJSON() { + return json; + } + + /** + * Set JSON + * + * @param json JSON object + * @return Api client + */ + public ApiClient setJSON(JSON json) { + this.json = json; + return this; + } + + /** + * True if isVerifyingSsl flag is on + * + * @return True if isVerifySsl flag is on + */ + public boolean isVerifyingSsl() { + return verifyingSsl; + } + + /** + * Configure whether to verify certificate and hostname when making https requests. + * Default to true. + * NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks. + * + * @param verifyingSsl True to verify TLS/SSL connection + * @return ApiClient + */ + public ApiClient setVerifyingSsl(boolean verifyingSsl) { + this.verifyingSsl = verifyingSsl; + applySslSettings(); + return this; + } + + /** + * Get SSL CA cert. + * + * @return Input stream to the SSL CA cert + */ + public InputStream getSslCaCert() { + return sslCaCert; + } + + /** + * Configure the CA certificate to be trusted when making https requests. + * Use null to reset to default. + * + * @param sslCaCert input stream for SSL CA cert + * @return ApiClient + */ + public ApiClient setSslCaCert(InputStream sslCaCert) { + this.sslCaCert = sslCaCert; + applySslSettings(); + return this; + } + + /** + *

Getter for the field keyManagers.

+ * + * @return an array of {@link javax.net.ssl.KeyManager} objects + */ + public KeyManager[] getKeyManagers() { + return keyManagers; + } + + /** + * Configure client keys to use for authorization in an SSL session. + * Use null to reset to default. + * + * @param managers The KeyManagers to use + * @return ApiClient + */ + public ApiClient setKeyManagers(KeyManager[] managers) { + this.keyManagers = managers; + applySslSettings(); + return this; + } + + /** + *

Getter for the field dateFormat.

+ * + * @return a {@link java.text.DateFormat} object + */ + public DateFormat getDateFormat() { + return dateFormat; + } + + /** + *

Setter for the field dateFormat.

+ * + * @param dateFormat a {@link java.text.DateFormat} object + * @return a {@link eu.openanalytics.containerproxy.backend.spcs.client.ApiClient} object + */ + public ApiClient setDateFormat(DateFormat dateFormat) { + JSON.setDateFormat(dateFormat); + return this; + } + + /** + *

Set SqlDateFormat.

+ * + * @param dateFormat a {@link java.text.DateFormat} object + * @return a {@link eu.openanalytics.containerproxy.backend.spcs.client.ApiClient} object + */ + public ApiClient setSqlDateFormat(DateFormat dateFormat) { + JSON.setSqlDateFormat(dateFormat); + return this; + } + + /** + *

Set OffsetDateTimeFormat.

+ * + * @param dateFormat a {@link java.time.format.DateTimeFormatter} object + * @return a {@link eu.openanalytics.containerproxy.backend.spcs.client.ApiClient} object + */ + public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + JSON.setOffsetDateTimeFormat(dateFormat); + return this; + } + + /** + *

Set LocalDateFormat.

+ * + * @param dateFormat a {@link java.time.format.DateTimeFormatter} object + * @return a {@link eu.openanalytics.containerproxy.backend.spcs.client.ApiClient} object + */ + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + JSON.setLocalDateFormat(dateFormat); + return this; + } + + /** + *

Set LenientOnJson.

+ * + * @param lenientOnJson a boolean + * @return a {@link eu.openanalytics.containerproxy.backend.spcs.client.ApiClient} object + */ + public ApiClient setLenientOnJson(boolean lenientOnJson) { + JSON.setLenientOnJson(lenientOnJson); + return this; + } + + /** + * Get authentications (key: authentication name, value: authentication). + * + * @return Map of authentication objects + */ + public Map getAuthentications() { + return authentications; + } + + /** + * Get authentication for the given name. + * + * @param authName The authentication name + * @return The authentication, null if not found + */ + public Authentication getAuthentication(String authName) { + return authentications.get(authName); + } + + /** + * Helper method to set access token for the first Bearer authentication. + * @param bearerToken Bearer token + */ + public void setBearerToken(String bearerToken) { + setBearerToken(() -> bearerToken); + } + + /** + * Helper method to set the supplier of access tokens for Bearer authentication. + * + * @param tokenSupplier The supplier of bearer tokens + */ + public void setBearerToken(Supplier tokenSupplier) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBearerAuth) { + ((HttpBearerAuth) auth).setBearerToken(tokenSupplier); + return; + } + } + throw new RuntimeException("No Bearer authentication configured!"); + } + + /** + * Helper method to set username for the first HTTP basic authentication. + * + * @param username Username + */ + public void setUsername(String username) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setUsername(username); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set password for the first HTTP basic authentication. + * + * @param password Password + */ + public void setPassword(String password) { + for (Authentication auth : authentications.values()) { + if (auth instanceof HttpBasicAuth) { + ((HttpBasicAuth) auth).setPassword(password); + return; + } + } + throw new RuntimeException("No HTTP basic authentication configured!"); + } + + /** + * Helper method to set API key value for the first API key authentication. + * + * @param apiKey API key + */ + public void setApiKey(String apiKey) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKey(apiKey); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set API key prefix for the first API key authentication. + * + * @param apiKeyPrefix API key prefix + */ + public void setApiKeyPrefix(String apiKeyPrefix) { + for (Authentication auth : authentications.values()) { + if (auth instanceof ApiKeyAuth) { + ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); + return; + } + } + throw new RuntimeException("No API key authentication configured!"); + } + + /** + * Helper method to set access token for the first OAuth2 authentication. + * + * @param accessToken Access token + */ + public void setAccessToken(String accessToken) { + for (Authentication auth : authentications.values()) { + if (auth instanceof OAuth) { + ((OAuth) auth).setAccessToken(accessToken); + return; + } + } + throw new RuntimeException("No OAuth2 authentication configured!"); + } + + /** + * Helper method to set credentials for AWSV4 Signature + * + * @param accessKey Access Key + * @param secretKey Secret Key + * @param region Region + * @param service Service to access to + */ + public void setAWS4Configuration(String accessKey, String secretKey, String region, String service) { + throw new RuntimeException("No AWS4 authentication configured!"); + } + + /** + * Helper method to set credentials for AWSV4 Signature + * + * @param accessKey Access Key + * @param secretKey Secret Key + * @param sessionToken Session Token + * @param region Region + * @param service Service to access to + */ + public void setAWS4Configuration(String accessKey, String secretKey, String sessionToken, String region, String service) { + throw new RuntimeException("No AWS4 authentication configured!"); + } + + /** + * Set the User-Agent header's value (by adding to the default header map). + * + * @param userAgent HTTP request's user agent + * @return ApiClient + */ + public ApiClient setUserAgent(String userAgent) { + addDefaultHeader("User-Agent", userAgent); + return this; + } + + /** + * Add a default header. + * + * @param key The header's key + * @param value The header's value + * @return ApiClient + */ + public ApiClient addDefaultHeader(String key, String value) { + defaultHeaderMap.put(key, value); + return this; + } + + /** + * Add a default cookie. + * + * @param key The cookie's key + * @param value The cookie's value + * @return ApiClient + */ + public ApiClient addDefaultCookie(String key, String value) { + defaultCookieMap.put(key, value); + return this; + } + + /** + * Check that whether debugging is enabled for this API client. + * + * @return True if debugging is enabled, false otherwise. + */ + public boolean isDebugging() { + return debugging; + } + + /** + * Enable/disable debugging for this API client. + * + * @param debugging To enable (true) or disable (false) debugging + * @return ApiClient + */ + public ApiClient setDebugging(boolean debugging) { + if (debugging != this.debugging) { + if (debugging) { + loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(Level.BODY); + httpClient = httpClient.newBuilder().addInterceptor(loggingInterceptor).build(); + } else { + final OkHttpClient.Builder builder = httpClient.newBuilder(); + builder.interceptors().remove(loggingInterceptor); + httpClient = builder.build(); + loggingInterceptor = null; + } + } + this.debugging = debugging; + return this; + } + + /** + * The path of temporary folder used to store downloaded files from endpoints + * with file response. The default value is null, i.e. using + * the system's default temporary folder. + * + * @see createTempFile + * @return Temporary folder path + */ + public String getTempFolderPath() { + return tempFolderPath; + } + + /** + * Set the temporary folder path (for downloading files) + * + * @param tempFolderPath Temporary folder path + * @return ApiClient + */ + public ApiClient setTempFolderPath(String tempFolderPath) { + this.tempFolderPath = tempFolderPath; + return this; + } + + /** + * Get connection timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getConnectTimeout() { + return httpClient.connectTimeoutMillis(); + } + + /** + * Sets the connect timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link java.lang.Integer#MAX_VALUE}. + * + * @param connectionTimeout connection timeout in milliseconds + * @return Api client + */ + public ApiClient setConnectTimeout(int connectionTimeout) { + httpClient = httpClient.newBuilder().connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS).build(); + return this; + } + + /** + * Get read timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getReadTimeout() { + return httpClient.readTimeoutMillis(); + } + + /** + * Sets the read timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link java.lang.Integer#MAX_VALUE}. + * + * @param readTimeout read timeout in milliseconds + * @return Api client + */ + public ApiClient setReadTimeout(int readTimeout) { + httpClient = httpClient.newBuilder().readTimeout(readTimeout, TimeUnit.MILLISECONDS).build(); + return this; + } + + /** + * Get write timeout (in milliseconds). + * + * @return Timeout in milliseconds + */ + public int getWriteTimeout() { + return httpClient.writeTimeoutMillis(); + } + + /** + * Sets the write timeout (in milliseconds). + * A value of 0 means no timeout, otherwise values must be between 1 and + * {@link java.lang.Integer#MAX_VALUE}. + * + * @param writeTimeout connection timeout in milliseconds + * @return Api client + */ + public ApiClient setWriteTimeout(int writeTimeout) { + httpClient = httpClient.newBuilder().writeTimeout(writeTimeout, TimeUnit.MILLISECONDS).build(); + return this; + } + + /** + * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) + * + * @return Token request builder + */ + public TokenRequestBuilder getTokenEndPoint() { + for (Authentication apiAuth : authentications.values()) { + if (apiAuth instanceof RetryingOAuth) { + RetryingOAuth retryingOAuth = (RetryingOAuth) apiAuth; + return retryingOAuth.getTokenRequestBuilder(); + } + } + return null; + } + + /** + * Format the given parameter object into string. + * + * @param param Parameter + * @return String representation of the parameter + */ + public String parameterToString(Object param) { + if (param == null) { + return ""; + } else if (param instanceof Date || param instanceof OffsetDateTime || param instanceof LocalDate) { + //Serialize to json string and remove the " enclosing characters + String jsonStr = JSON.serialize(param); + return jsonStr.substring(1, jsonStr.length() - 1); + } else if (param instanceof Collection) { + StringBuilder b = new StringBuilder(); + for (Object o : (Collection) param) { + if (b.length() > 0) { + b.append(","); + } + b.append(o); + } + return b.toString(); + } else { + return String.valueOf(param); + } + } + + /** + * Formats the specified query parameter to a list containing a single {@code Pair} object. + * + * Note that {@code value} must not be a collection. + * + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list containing a single {@code Pair} object. + */ + public List parameterToPair(String name, Object value) { + List params = new ArrayList(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value instanceof Collection) { + return params; + } + + params.add(new Pair(name, parameterToString(value))); + return params; + } + + /** + * Formats the specified collection query parameters to a list of {@code Pair} objects. + * + * Note that the values of each of the returned Pair objects are percent-encoded. + * + * @param collectionFormat The collection format of the parameter. + * @param name The name of the parameter. + * @param value The value of the parameter. + * @return A list of {@code Pair} objects. + */ + public List parameterToPairs(String collectionFormat, String name, Collection value) { + List params = new ArrayList(); + + // preconditions + if (name == null || name.isEmpty() || value == null || value.isEmpty()) { + return params; + } + + // create the params based on the collection format + if ("multi".equals(collectionFormat)) { + for (Object item : value) { + params.add(new Pair(name, escapeString(parameterToString(item)))); + } + return params; + } + + // collectionFormat is assumed to be "csv" by default + String delimiter = ","; + + // escape all delimiters except commas, which are URI reserved + // characters + if ("ssv".equals(collectionFormat)) { + delimiter = escapeString(" "); + } else if ("tsv".equals(collectionFormat)) { + delimiter = escapeString("\t"); + } else if ("pipes".equals(collectionFormat)) { + delimiter = escapeString("|"); + } + + StringBuilder sb = new StringBuilder(); + for (Object item : value) { + sb.append(delimiter); + sb.append(escapeString(parameterToString(item))); + } + + params.add(new Pair(name, sb.substring(delimiter.length()))); + + return params; + } + + /** + * Formats the specified free-form query parameters to a list of {@code Pair} objects. + * + * @param value The free-form query parameters. + * @return A list of {@code Pair} objects. + */ + public List freeFormParameterToPairs(Object value) { + List params = new ArrayList<>(); + + // preconditions + if (value == null || !(value instanceof Map )) { + return params; + } + + @SuppressWarnings("unchecked") + final Map valuesMap = (Map) value; + + for (Map.Entry entry : valuesMap.entrySet()) { + params.add(new Pair(entry.getKey(), parameterToString(entry.getValue()))); + } + + return params; + } + + + /** + * Formats the specified collection path parameter to a string value. + * + * @param collectionFormat The collection format of the parameter. + * @param value The value of the parameter. + * @return String representation of the parameter + */ + public String collectionPathParameterToString(String collectionFormat, Collection value) { + // create the value based on the collection format + if ("multi".equals(collectionFormat)) { + // not valid for path params + return parameterToString(value); + } + + // collectionFormat is assumed to be "csv" by default + String delimiter = ","; + + if ("ssv".equals(collectionFormat)) { + delimiter = " "; + } else if ("tsv".equals(collectionFormat)) { + delimiter = "\t"; + } else if ("pipes".equals(collectionFormat)) { + delimiter = "|"; + } + + StringBuilder sb = new StringBuilder() ; + for (Object item : value) { + sb.append(delimiter); + sb.append(parameterToString(item)); + } + + return sb.substring(delimiter.length()); + } + + /** + * Sanitize filename by removing path. + * e.g. ../../sun.gif becomes sun.gif + * + * @param filename The filename to be sanitized + * @return The sanitized filename + */ + public String sanitizeFilename(String filename) { + return filename.replaceFirst("^.*[/\\\\]", ""); + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * "* / *" is also default to JSON + * @param mime MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public boolean isJsonMime(String mime) { + String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; + return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); + } + + /** + * Select the Accept header's value from the given accepts array: + * if JSON exists in the given array, use it; + * otherwise use all of them (joining into a string) + * + * @param accepts The accepts array to select from + * @return The Accept header to use. If the given array is empty, + * null will be returned (not to set the Accept header explicitly). + */ + public String selectHeaderAccept(String[] accepts) { + if (accepts.length == 0) { + return null; + } + for (String accept : accepts) { + if (isJsonMime(accept)) { + return accept; + } + } + return StringUtil.join(accepts, ","); + } + + /** + * Select the Content-Type header's value from the given array: + * if JSON exists in the given array, use it; + * otherwise use the first one of the array. + * + * @param contentTypes The Content-Type array to select from + * @return The Content-Type header to use. If the given array is empty, + * returns null. If it matches "any", JSON will be used. + */ + public String selectHeaderContentType(String[] contentTypes) { + if (contentTypes.length == 0) { + return null; + } + + if (contentTypes[0].equals("*/*")) { + return "application/json"; + } + + for (String contentType : contentTypes) { + if (isJsonMime(contentType)) { + return contentType; + } + } + + return contentTypes[0]; + } + + /** + * Escape the given string to be used as URL query value. + * + * @param str String to be escaped + * @return Escaped string + */ + public String escapeString(String str) { + try { + return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); + } catch (UnsupportedEncodingException e) { + return str; + } + } + + /** + * Deserialize response body to Java object, according to the return type and + * the Content-Type response header. + * + * @param Type + * @param response HTTP response + * @param returnType The type of the Java object + * @return The deserialized Java object + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to deserialize response body, i.e. cannot read response body + * or the Content-Type of the response is not supported. + */ + @SuppressWarnings("unchecked") + public T deserialize(Response response, Type returnType) throws ApiException { + if (response == null || returnType == null) { + return null; + } + + if ("byte[]".equals(returnType.toString())) { + // Handle binary response (byte array). + try { + return (T) response.body().bytes(); + } catch (IOException e) { + throw new ApiException(e); + } + } else if (returnType.equals(File.class)) { + // Handle file downloading. + return (T) downloadFileFromResponse(response); + } + + ResponseBody respBody = response.body(); + if (respBody == null) { + return null; + } + + String contentType = response.headers().get("Content-Type"); + if (contentType == null) { + // ensuring a default content type + contentType = "application/json"; + } + try { + if (isJsonMime(contentType)) { + return JSON.deserialize(respBody.byteStream(), returnType); + } else if (returnType.equals(String.class)) { + String respBodyString = respBody.string(); + if (respBodyString.isEmpty()) { + return null; + } + // Expecting string, return the raw response body. + return (T) respBodyString; + } else { + throw new ApiException( + "Content type \"" + contentType + "\" is not supported for type: " + returnType, + response.code(), + response.headers().toMultimap(), + response.body().string()); + } + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * Serialize the given Java object into request body according to the object's + * class and the request Content-Type. + * + * @param obj The Java object + * @param contentType The request Content-Type + * @return The serialized request body + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to serialize the given object + */ + public RequestBody serialize(Object obj, String contentType) throws ApiException { + if (obj instanceof byte[]) { + // Binary (byte array) body parameter support. + return RequestBody.create((byte[]) obj, MediaType.parse(contentType)); + } else if (obj instanceof File) { + // File body parameter support. + return RequestBody.create((File) obj, MediaType.parse(contentType)); + } else if ("text/plain".equals(contentType) && obj instanceof String) { + return RequestBody.create((String) obj, MediaType.parse(contentType)); + } else if (isJsonMime(contentType)) { + String content; + if (obj != null) { + content = JSON.serialize(obj); + } else { + content = null; + } + return RequestBody.create(content, MediaType.parse(contentType)); + } else if (obj instanceof String) { + return RequestBody.create((String) obj, MediaType.parse(contentType)); + } else { + throw new ApiException("Content type \"" + contentType + "\" is not supported"); + } + } + + /** + * Download file from the given response. + * + * @param response An instance of the Response object + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to read file content from response and write to disk + * @return Downloaded file + */ + public File downloadFileFromResponse(Response response) throws ApiException { + try { + File file = prepareDownloadFile(response); + BufferedSink sink = Okio.buffer(Okio.sink(file)); + sink.writeAll(response.body().source()); + sink.close(); + return file; + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * Prepare file for download + * + * @param response An instance of the Response object + * @return Prepared file for the download + * @throws java.io.IOException If fail to prepare file for download + */ + public File prepareDownloadFile(Response response) throws IOException { + String filename = null; + String contentDisposition = response.header("Content-Disposition"); + if (contentDisposition != null && !"".equals(contentDisposition)) { + // Get filename from the Content-Disposition header. + Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); + Matcher matcher = pattern.matcher(contentDisposition); + if (matcher.find()) { + filename = sanitizeFilename(matcher.group(1)); + } + } + + String prefix = null; + String suffix = null; + if (filename == null) { + prefix = "download-"; + suffix = ""; + } else { + int pos = filename.lastIndexOf("."); + if (pos == -1) { + prefix = filename + "-"; + } else { + prefix = filename.substring(0, pos) + "-"; + suffix = filename.substring(pos); + } + // Files.createTempFile requires the prefix to be at least three characters long + if (prefix.length() < 3) + prefix = "download-"; + } + + if (tempFolderPath == null) + return Files.createTempFile(prefix, suffix).toFile(); + else + return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); + } + + /** + * {@link #execute(Call, Type)} + * + * @param Type + * @param call An instance of the Call object + * @return ApiResponse<T> + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to execute the call + */ + public ApiResponse execute(Call call) throws ApiException { + return execute(call, null); + } + + /** + * Execute HTTP call and deserialize the HTTP response body into the given return type. + * + * @param returnType The return type used to deserialize HTTP response body + * @param The return type corresponding to (same with) returnType + * @param call Call + * @return ApiResponse object containing response status, headers and + * data, which is a Java object deserialized from response body and would be null + * when returnType is null. + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to execute the call + */ + public ApiResponse execute(Call call, Type returnType) throws ApiException { + try { + Response response = call.execute(); + T data = handleResponse(response, returnType); + return new ApiResponse(response.code(), response.headers().toMultimap(), data); + } catch (IOException e) { + throw new ApiException(e); + } + } + + /** + * {@link #executeAsync(Call, Type, ApiCallback)} + * + * @param Type + * @param call An instance of the Call object + * @param callback ApiCallback<T> + */ + public void executeAsync(Call call, ApiCallback callback) { + executeAsync(call, null, callback); + } + + /** + * Execute HTTP call asynchronously. + * + * @param Type + * @param call The callback to be executed when the API call finishes + * @param returnType Return type + * @param callback ApiCallback + * @see #execute(Call, Type) + */ + @SuppressWarnings("unchecked") + public void executeAsync(Call call, final Type returnType, final ApiCallback callback) { + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + callback.onFailure(new ApiException(e), 0, null); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + T result; + try { + result = (T) handleResponse(response, returnType); + } catch (ApiException e) { + callback.onFailure(e, response.code(), response.headers().toMultimap()); + return; + } catch (Exception e) { + callback.onFailure(new ApiException(e), response.code(), response.headers().toMultimap()); + return; + } + callback.onSuccess(result, response.code(), response.headers().toMultimap()); + } + }); + } + + /** + * Handle the given response, return the deserialized object when the response is successful. + * + * @param Type + * @param response Response + * @param returnType Return type + * @return Type + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If the response has an unsuccessful status code or + * fail to deserialize the response body + */ + public T handleResponse(Response response, Type returnType) throws ApiException { + if (response.isSuccessful()) { + if (returnType == null || response.code() == 204) { + // returning null if the returnType is not defined, + // or the status code is 204 (No Content) + if (response.body() != null) { + try { + response.body().close(); + } catch (Exception e) { + throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); + } + } + return null; + } else { + return deserialize(response, returnType); + } + } else { + String respBody = null; + if (response.body() != null) { + try { + respBody = response.body().string(); + } catch (IOException e) { + throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); + } + } + throw new ApiException(response.message(), response.code(), response.headers().toMultimap(), respBody); + } + } + + /** + * Build HTTP call with the given options. + * + * @param baseUrl The base URL + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param cookieParams The cookie parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param callback Callback for upload/download progress + * @return The HTTP call + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to serialize the request body object + */ + public Call buildCall(String baseUrl, String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException { + Request request = buildRequest(baseUrl, path, method, queryParams, collectionQueryParams, body, headerParams, cookieParams, formParams, authNames, callback); + + return httpClient.newCall(request); + } + + /** + * Build an HTTP request with the given options. + * + * @param baseUrl The base URL + * @param path The sub-path of the HTTP URL + * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @param body The request body object + * @param headerParams The header parameters + * @param cookieParams The cookie parameters + * @param formParams The form parameters + * @param authNames The authentications to apply + * @param callback Callback for upload/download progress + * @return The HTTP request + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to serialize the request body object + */ + public Request buildRequest(String baseUrl, String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException { + final String url = buildUrl(baseUrl, path, queryParams, collectionQueryParams); + + // prepare HTTP request body + RequestBody reqBody; + String contentType = headerParams.get("Content-Type"); + String contentTypePure = contentType; + if (contentTypePure != null && contentTypePure.contains(";")) { + contentTypePure = contentType.substring(0, contentType.indexOf(";")); + } + if (!HttpMethod.permitsRequestBody(method)) { + reqBody = null; + } else if ("application/x-www-form-urlencoded".equals(contentTypePure)) { + reqBody = buildRequestBodyFormEncoding(formParams); + } else if ("multipart/form-data".equals(contentTypePure)) { + reqBody = buildRequestBodyMultipart(formParams); + } else if (body == null) { + if ("DELETE".equals(method)) { + // allow calling DELETE without sending a request body + reqBody = null; + } else { + // use an empty request body (for POST, PUT and PATCH) + reqBody = RequestBody.create("", contentType == null ? null : MediaType.parse(contentType)); + } + } else { + reqBody = serialize(body, contentType); + } + + List updatedQueryParams = new ArrayList<>(queryParams); + + // update parameters with authentication settings + updateParamsForAuth(authNames, updatedQueryParams, headerParams, cookieParams, requestBodyToString(reqBody), method, URI.create(url)); + + final Request.Builder reqBuilder = new Request.Builder().url(buildUrl(baseUrl, path, updatedQueryParams, collectionQueryParams)); + processHeaderParams(headerParams, reqBuilder); + processCookieParams(cookieParams, reqBuilder); + + // Associate callback with request (if not null) so interceptor can + // access it when creating ProgressResponseBody + reqBuilder.tag(callback); + + Request request = null; + + if (callback != null && reqBody != null) { + ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, callback); + request = reqBuilder.method(method, progressRequestBody).build(); + } else { + request = reqBuilder.method(method, reqBody).build(); + } + + return request; + } + + /** + * Build full URL by concatenating base path, the given sub path and query parameters. + * + * @param baseUrl The base URL + * @param path The sub path + * @param queryParams The query parameters + * @param collectionQueryParams The collection query parameters + * @return The full URL + */ + public String buildUrl(String baseUrl, String path, List queryParams, List collectionQueryParams) { + final StringBuilder url = new StringBuilder(); + if (baseUrl != null) { + url.append(baseUrl).append(path); + } else { + String baseURL; + if (serverIndex != null) { + if (serverIndex < 0 || serverIndex >= servers.size()) { + throw new ArrayIndexOutOfBoundsException(String.format( + Locale.ROOT, + "Invalid index %d when selecting the host settings. Must be less than %d", serverIndex, servers.size() + )); + } + baseURL = servers.get(serverIndex).URL(serverVariables); + } else { + baseURL = basePath; + } + url.append(baseURL).append(path); + } + + if (queryParams != null && !queryParams.isEmpty()) { + // support (constant) query string in `path`, e.g. "/posts?draft=1" + String prefix = path.contains("?") ? "&" : "?"; + for (Pair param : queryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + url.append(escapeString(param.getName())).append("=").append(escapeString(value)); + } + } + } + + if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) { + String prefix = url.toString().contains("?") ? "&" : "?"; + for (Pair param : collectionQueryParams) { + if (param.getValue() != null) { + if (prefix != null) { + url.append(prefix); + prefix = null; + } else { + url.append("&"); + } + String value = parameterToString(param.getValue()); + // collection query parameter value already escaped as part of parameterToPairs + url.append(escapeString(param.getName())).append("=").append(value); + } + } + } + + return url.toString(); + } + + /** + * Set header parameters to the request builder, including default headers. + * + * @param headerParams Header parameters in the form of Map + * @param reqBuilder Request.Builder + */ + public void processHeaderParams(Map headerParams, Request.Builder reqBuilder) { + for (Entry param : headerParams.entrySet()) { + reqBuilder.header(param.getKey(), parameterToString(param.getValue())); + } + for (Entry header : defaultHeaderMap.entrySet()) { + if (!headerParams.containsKey(header.getKey())) { + reqBuilder.header(header.getKey(), parameterToString(header.getValue())); + } + } + } + + /** + * Set cookie parameters to the request builder, including default cookies. + * + * @param cookieParams Cookie parameters in the form of Map + * @param reqBuilder Request.Builder + */ + public void processCookieParams(Map cookieParams, Request.Builder reqBuilder) { + for (Entry param : cookieParams.entrySet()) { + reqBuilder.addHeader("Cookie", String.format(Locale.ROOT, "%s=%s", param.getKey(), param.getValue())); + } + for (Entry param : defaultCookieMap.entrySet()) { + if (!cookieParams.containsKey(param.getKey())) { + reqBuilder.addHeader("Cookie", String.format(Locale.ROOT, "%s=%s", param.getKey(), param.getValue())); + } + } + } + + /** + * Update query and header parameters based on authentication settings. + * + * @param authNames The authentications to apply + * @param queryParams List of query parameters + * @param headerParams Map of header parameters + * @param cookieParams Map of cookie parameters + * @param payload HTTP request body + * @param method HTTP method + * @param uri URI + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fails to update the parameters + */ + public void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams, + Map cookieParams, String payload, String method, URI uri) throws ApiException { + for (String authName : authNames) { + Authentication auth = authentications.get(authName); + if (auth == null) { + throw new RuntimeException("Authentication undefined: " + authName); + } + auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri); + } + } + + /** + * Build a form-encoding request body with the given form parameters. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + public RequestBody buildRequestBodyFormEncoding(Map formParams) { + okhttp3.FormBody.Builder formBuilder = new okhttp3.FormBody.Builder(); + for (Entry param : formParams.entrySet()) { + formBuilder.add(param.getKey(), parameterToString(param.getValue())); + } + return formBuilder.build(); + } + + /** + * Build a multipart (file uploading) request body with the given form parameters, + * which could contain text fields and file fields. + * + * @param formParams Form parameters in the form of Map + * @return RequestBody + */ + public RequestBody buildRequestBodyMultipart(Map formParams) { + MultipartBody.Builder mpBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); + for (Entry param : formParams.entrySet()) { + if (param.getValue() instanceof File) { + File file = (File) param.getValue(); + addPartToMultiPartBuilder(mpBuilder, param.getKey(), file); + } else if (param.getValue() instanceof List) { + List list = (List) param.getValue(); + for (Object item: list) { + if (item instanceof File) { + addPartToMultiPartBuilder(mpBuilder, param.getKey(), (File) item); + } else { + addPartToMultiPartBuilder(mpBuilder, param.getKey(), param.getValue()); + } + } + } else { + addPartToMultiPartBuilder(mpBuilder, param.getKey(), param.getValue()); + } + } + return mpBuilder.build(); + } + + /** + * Guess Content-Type header from the given file (defaults to "application/octet-stream"). + * + * @param file The given file + * @return The guessed Content-Type + */ + public String guessContentTypeFromFile(File file) { + String contentType = URLConnection.guessContentTypeFromName(file.getName()); + if (contentType == null) { + return "application/octet-stream"; + } else { + return contentType; + } + } + + /** + * Add a Content-Disposition Header for the given key and file to the MultipartBody Builder. + * + * @param mpBuilder MultipartBody.Builder + * @param key The key of the Header element + * @param file The file to add to the Header + */ + protected void addPartToMultiPartBuilder(MultipartBody.Builder mpBuilder, String key, File file) { + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + key + "\"; filename=\"" + file.getName() + "\""); + MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file)); + mpBuilder.addPart(partHeaders, RequestBody.create(file, mediaType)); + } + + /** + * Add a Content-Disposition Header for the given key and complex object to the MultipartBody Builder. + * + * @param mpBuilder MultipartBody.Builder + * @param key The key of the Header element + * @param obj The complex object to add to the Header + */ + protected void addPartToMultiPartBuilder(MultipartBody.Builder mpBuilder, String key, Object obj) { + RequestBody requestBody; + if (obj instanceof String) { + requestBody = RequestBody.create((String) obj, MediaType.parse("text/plain")); + } else { + String content; + if (obj != null) { + content = JSON.serialize(obj); + } else { + content = null; + } + requestBody = RequestBody.create(content, MediaType.parse("application/json")); + } + + Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""); + mpBuilder.addPart(partHeaders, requestBody); + } + + /** + * Get network interceptor to add it to the httpClient to track download progress for + * async requests. + */ + protected Interceptor getProgressInterceptor() { + return new Interceptor() { + @Override + public Response intercept(Interceptor.Chain chain) throws IOException { + final Request request = chain.request(); + final Response originalResponse = chain.proceed(request); + if (request.tag() instanceof ApiCallback) { + final ApiCallback callback = (ApiCallback) request.tag(); + return originalResponse.newBuilder() + .body(new ProgressResponseBody(originalResponse.body(), callback)) + .build(); + } + return originalResponse; + } + }; + } + + /** + * Apply SSL related settings to httpClient according to the current values of + * verifyingSsl and sslCaCert. + */ + protected void applySslSettings() { + try { + TrustManager[] trustManagers; + HostnameVerifier hostnameVerifier; + if (!verifyingSsl) { + trustManagers = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + } else { + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + + if (sslCaCert == null) { + trustManagerFactory.init((KeyStore) null); + } else { + char[] password = null; // Any password will work. + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + Collection certificates = certificateFactory.generateCertificates(sslCaCert); + if (certificates.isEmpty()) { + throw new IllegalArgumentException("expected non-empty set of trusted certificates"); + } + KeyStore caKeyStore = newEmptyKeyStore(password); + int index = 0; + for (Certificate certificate : certificates) { + String certificateAlias = "ca" + (index++); + caKeyStore.setCertificateEntry(certificateAlias, certificate); + } + trustManagerFactory.init(caKeyStore); + } + trustManagers = trustManagerFactory.getTrustManagers(); + hostnameVerifier = OkHostnameVerifier.INSTANCE; + } + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagers, trustManagers, new SecureRandom()); + httpClient = httpClient.newBuilder() + .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0]) + .hostnameVerifier(hostnameVerifier) + .build(); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } + } + + protected KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, password); + return keyStore; + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** + * Convert the HTTP request body to a string. + * + * @param requestBody The HTTP request object + * @return The string representation of the HTTP request body + * @throws eu.openanalytics.containerproxy.backend.spcs.client.ApiException If fail to serialize the request body object into a string + */ + protected String requestBodyToString(RequestBody requestBody) throws ApiException { + if (requestBody != null) { + try { + final Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + return buffer.readUtf8(); + } catch (final IOException e) { + throw new ApiException(e); + } + } + + // empty http request body + return ""; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiException.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiException.java new file mode 100644 index 00000000..f1990992 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiException.java @@ -0,0 +1,168 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.Map; +import java.util.List; +import java.util.Locale; + + +/** + *

ApiException class.

+ */ +@SuppressWarnings("serial") +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ApiException extends Exception { + private static final long serialVersionUID = 1L; + + private int code = 0; + private Map> responseHeaders = null; + private String responseBody = null; + + /** + *

Constructor for ApiException.

+ */ + public ApiException() {} + + /** + *

Constructor for ApiException.

+ * + * @param throwable a {@link java.lang.Throwable} object + */ + public ApiException(Throwable throwable) { + super(throwable); + } + + /** + *

Constructor for ApiException.

+ * + * @param message the error message + */ + public ApiException(String message) { + super(message); + } + + /** + *

Constructor for ApiException.

+ * + * @param message the error message + * @param throwable a {@link java.lang.Throwable} object + * @param code HTTP status code + * @param responseHeaders a {@link java.util.Map} of HTTP response headers + * @param responseBody the response body + */ + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders, String responseBody) { + super(message, throwable); + this.code = code; + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + /** + *

Constructor for ApiException.

+ * + * @param message the error message + * @param code HTTP status code + * @param responseHeaders a {@link java.util.Map} of HTTP response headers + * @param responseBody the response body + */ + public ApiException(String message, int code, Map> responseHeaders, String responseBody) { + this(message, (Throwable) null, code, responseHeaders, responseBody); + } + + /** + *

Constructor for ApiException.

+ * + * @param message the error message + * @param throwable a {@link java.lang.Throwable} object + * @param code HTTP status code + * @param responseHeaders a {@link java.util.Map} of HTTP response headers + */ + public ApiException(String message, Throwable throwable, int code, Map> responseHeaders) { + this(message, throwable, code, responseHeaders, null); + } + + /** + *

Constructor for ApiException.

+ * + * @param code HTTP status code + * @param responseHeaders a {@link java.util.Map} of HTTP response headers + * @param responseBody the response body + */ + public ApiException(int code, Map> responseHeaders, String responseBody) { + this("Response Code: " + code + " Response Body: " + responseBody, (Throwable) null, code, responseHeaders, responseBody); + } + + /** + *

Constructor for ApiException.

+ * + * @param code HTTP status code + * @param message a {@link java.lang.String} object + */ + public ApiException(int code, String message) { + super(message); + this.code = code; + } + + /** + *

Constructor for ApiException.

+ * + * @param code HTTP status code + * @param message the error message + * @param responseHeaders a {@link java.util.Map} of HTTP response headers + * @param responseBody the response body + */ + public ApiException(int code, String message, Map> responseHeaders, String responseBody) { + this(code, message); + this.responseHeaders = responseHeaders; + this.responseBody = responseBody; + } + + /** + * Get the HTTP status code. + * + * @return HTTP status code + */ + public int getCode() { + return code; + } + + /** + * Get the HTTP response headers. + * + * @return A map of list of string + */ + public Map> getResponseHeaders() { + return responseHeaders; + } + + /** + * Get the HTTP response body. + * + * @return Response body in the form of string + */ + public String getResponseBody() { + return responseBody; + } + + /** + * Get the exception message including HTTP response data. + * + * @return The exception message + */ + public String getMessage() { + return String.format(Locale.ROOT, "Message: %s%nHTTP response code: %s%nHTTP response body: %s%nHTTP response headers: %s", + super.getMessage(), this.getCode(), this.getResponseBody(), this.getResponseHeaders()); + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiResponse.java new file mode 100644 index 00000000..73d02b56 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ApiResponse.java @@ -0,0 +1,76 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.List; +import java.util.Map; + +/** + * API response returned by API call. + */ +public class ApiResponse { + final private int statusCode; + final private Map> headers; + final private T data; + + /** + *

Constructor for ApiResponse.

+ * + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + */ + public ApiResponse(int statusCode, Map> headers) { + this(statusCode, headers, null); + } + + /** + *

Constructor for ApiResponse.

+ * + * @param statusCode The status code of HTTP response + * @param headers The headers of HTTP response + * @param data The object deserialized from response bod + */ + public ApiResponse(int statusCode, Map> headers, T data) { + this.statusCode = statusCode; + this.headers = headers; + this.data = data; + } + + /** + *

Get the status code.

+ * + * @return the status code + */ + public int getStatusCode() { + return statusCode; + } + + /** + *

Get the headers.

+ * + * @return a {@link java.util.Map} of headers + */ + public Map> getHeaders() { + return headers; + } + + /** + *

Get the data.

+ * + * @return the data + */ + public T getData() { + return data; + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Configuration.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Configuration.java new file mode 100644 index 00000000..7a98da33 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Configuration.java @@ -0,0 +1,63 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class Configuration { + public static final String VERSION = "0.1.0"; + + private static final AtomicReference defaultApiClient = new AtomicReference<>(); + private static volatile Supplier apiClientFactory = ApiClient::new; + + /** + * Get the default API client, which would be used when creating API instances without providing an API client. + * + * @return Default API client + */ + public static ApiClient getDefaultApiClient() { + ApiClient client = defaultApiClient.get(); + if (client == null) { + client = defaultApiClient.updateAndGet(val -> { + if (val != null) { // changed by another thread + return val; + } + return apiClientFactory.get(); + }); + } + return client; + } + + /** + * Set the default API client, which would be used when creating API instances without providing an API client. + * + * @param apiClient API client + */ + public static void setDefaultApiClient(ApiClient apiClient) { + defaultApiClient.set(apiClient); + } + + /** + * set the callback used to create new ApiClient objects + */ + public static void setApiClientFactory(Supplier factory) { + apiClientFactory = Objects.requireNonNull(factory); + } + + private Configuration() { + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/GzipRequestInterceptor.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/GzipRequestInterceptor.java new file mode 100644 index 00000000..91c67995 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/GzipRequestInterceptor.java @@ -0,0 +1,85 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import okhttp3.*; +import okio.Buffer; +import okio.BufferedSink; +import okio.GzipSink; +import okio.Okio; + +import java.io.IOException; + +/** + * Encodes request bodies using gzip. + * + * Taken from https://github.com/square/okhttp/issues/350 + */ +class GzipRequestInterceptor implements Interceptor { + @Override + public Response intercept(Chain chain) throws IOException { + Request originalRequest = chain.request(); + if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) { + return chain.proceed(originalRequest); + } + + Request compressedRequest = originalRequest.newBuilder() + .header("Content-Encoding", "gzip") + .method(originalRequest.method(), forceContentLength(gzip(originalRequest.body()))) + .build(); + return chain.proceed(compressedRequest); + } + + private RequestBody forceContentLength(final RequestBody requestBody) throws IOException { + final Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + return new RequestBody() { + @Override + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() { + return buffer.size(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + sink.write(buffer.snapshot()); + } + }; + } + + private RequestBody gzip(final RequestBody body) { + return new RequestBody() { + @Override + public MediaType contentType() { + return body.contentType(); + } + + @Override + public long contentLength() { + return -1; // We don't know the compressed length in advance! + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + BufferedSink gzipSink = Okio.buffer(new GzipSink(sink)); + body.writeTo(gzipSink); + gzipSink.close(); + } + }; + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JSON.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JSON.java new file mode 100644 index 00000000..0bda0b81 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/JSON.java @@ -0,0 +1,430 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.internal.bind.util.ISO8601Utils; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonElement; +import io.gsonfire.GsonFireBuilder; +import io.gsonfire.TypeSelector; + +import okio.ByteString; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.HashMap; + +/* + * A JSON utility class + * + * NOTE: in the future, this class may be converted to static, which may break + * backward-compatibility + */ +public class JSON { + private static Gson gson; + private static boolean isLenientOnJson = false; + private static DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); + private static SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); + private static OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + private static LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + private static ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter(); + + @SuppressWarnings("unchecked") + public static GsonBuilder createGson() { + GsonFireBuilder fireBuilder = new GsonFireBuilder() + ; + GsonBuilder builder = fireBuilder.createGsonBuilder(); + return builder; + } + + private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) { + JsonElement element = readElement.getAsJsonObject().get(discriminatorField); + if (null == element) { + throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">"); + } + return element.getAsString(); + } + + /** + * Returns the Java class that implements the OpenAPI schema for the specified discriminator value. + * + * @param classByDiscriminatorValue The map of discriminator values to Java classes. + * @param discriminatorValue The value of the OpenAPI discriminator in the input data. + * @return The Java class that implements the OpenAPI schema + */ + private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) { + Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue); + if (null == clazz) { + throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">"); + } + return clazz; + } + + static { + GsonBuilder gsonBuilder = createGson(); + gsonBuilder.registerTypeAdapter(Date.class, dateTypeAdapter); + gsonBuilder.registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter); + gsonBuilder.registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter); + gsonBuilder.registerTypeAdapter(LocalDate.class, localDateTypeAdapter); + gsonBuilder.registerTypeAdapter(byte[].class, byteArrayAdapter); + gsonBuilder.registerTypeAdapterFactory(new eu.openanalytics.containerproxy.backend.spcs.client.model.ErrorResponse.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessAcceptedResponse.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessResponse.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec.CustomTypeAdapterFactory()); + gson = gsonBuilder.create(); + } + + /** + * Get Gson. + * + * @return Gson + */ + public static Gson getGson() { + return gson; + } + + /** + * Set Gson. + * + * @param gson Gson + */ + public static void setGson(Gson gson) { + JSON.gson = gson; + } + + public static void setLenientOnJson(boolean lenientOnJson) { + isLenientOnJson = lenientOnJson; + } + + /** + * Serialize the given Java object into JSON string. + * + * @param obj Object + * @return String representation of the JSON + */ + public static String serialize(Object obj) { + return gson.toJson(obj); + } + + /** + * Deserialize the given JSON string to Java object. + * + * @param Type + * @param body The JSON string + * @param returnType The type to deserialize into + * @return The deserialized Java object + */ + @SuppressWarnings("unchecked") + public static T deserialize(String body, Type returnType) { + try { + if (isLenientOnJson) { + JsonReader jsonReader = new JsonReader(new StringReader(body)); + // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) + jsonReader.setLenient(true); + return gson.fromJson(jsonReader, returnType); + } else { + return gson.fromJson(body, returnType); + } + } catch (JsonParseException e) { + // Fallback processing when failed to parse JSON form response body: + // return the response body string directly for the String return type; + if (returnType.equals(String.class)) { + return (T) body; + } else { + throw (e); + } + } + } + + /** + * Deserialize the given JSON InputStream to a Java object. + * + * @param Type + * @param inputStream The JSON InputStream + * @param returnType The type to deserialize into + * @return The deserialized Java object + */ + @SuppressWarnings("unchecked") + public static T deserialize(InputStream inputStream, Type returnType) throws IOException { + try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + if (isLenientOnJson) { + // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) + JsonReader jsonReader = new JsonReader(reader); + jsonReader.setLenient(true); + return gson.fromJson(jsonReader, returnType); + } else { + return gson.fromJson(reader, returnType); + } + } + } + + /** + * Gson TypeAdapter for Byte Array type + */ + public static class ByteArrayAdapter extends TypeAdapter { + + @Override + public void write(JsonWriter out, byte[] value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(ByteString.of(value).base64()); + } + } + + @Override + public byte[] read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String bytesAsBase64 = in.nextString(); + ByteString byteString = ByteString.decodeBase64(bytesAsBase64); + return byteString.toByteArray(); + } + } + } + + /** + * Gson TypeAdapter for JSR310 OffsetDateTime type + */ + public static class OffsetDateTimeTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public OffsetDateTimeTypeAdapter() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, OffsetDateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public OffsetDateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + if (date.endsWith("+0000")) { + date = date.substring(0, date.length()-5) + "Z"; + } + return OffsetDateTime.parse(date, formatter); + } + } + } + + /** + * Gson TypeAdapter for JSR310 LocalDate type + */ + public static class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(DateTimeFormatter.ISO_LOCAL_DATE); + } + + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return LocalDate.parse(date, formatter); + } + } + } + + public static void setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + offsetDateTimeTypeAdapter.setFormat(dateFormat); + } + + public static void setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + } + + /** + * Gson TypeAdapter for java.sql.Date type + * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used + * (more efficient than SimpleDateFormat). + */ + public static class SqlDateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public SqlDateTypeAdapter() {} + + public SqlDateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, java.sql.Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = date.toString(); + } + out.value(value); + } + } + + @Override + public java.sql.Date read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return new java.sql.Date(dateFormat.parse(date).getTime()); + } + return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } + } + + /** + * Gson TypeAdapter for java.util.Date type + * If the dateFormat is null, ISO8601Utils will be used. + */ + public static class DateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public DateTypeAdapter() {} + + public DateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = ISO8601Utils.format(date, true); + } + out.value(value); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + try { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return dateFormat.parse(date); + } + return ISO8601Utils.parse(date, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } + } + + public static void setDateFormat(DateFormat dateFormat) { + dateTypeAdapter.setFormat(dateFormat); + } + + public static void setSqlDateFormat(DateFormat dateFormat) { + sqlDateTypeAdapter.setFormat(dateFormat); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Pair.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Pair.java new file mode 100644 index 00000000..64eaeca4 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/Pair.java @@ -0,0 +1,38 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class Pair { + private final String name; + private final String value; + + public Pair(String name, String value) { + this.name = isValidString(name) ? name : ""; + this.value = isValidString(value) ? value : ""; + } + + public String getName() { + return this.name; + } + + public String getValue() { + return this.value; + } + + private static boolean isValidString(String arg) { + return arg != null; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressRequestBody.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressRequestBody.java new file mode 100644 index 00000000..486cf143 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressRequestBody.java @@ -0,0 +1,74 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import okhttp3.MediaType; +import okhttp3.RequestBody; + +import java.io.IOException; + +import okio.Buffer; +import okio.BufferedSink; +import okio.ForwardingSink; +import okio.Okio; +import okio.Sink; + +public class ProgressRequestBody extends RequestBody { + + private final RequestBody requestBody; + + private final ApiCallback callback; + + public ProgressRequestBody(RequestBody requestBody, ApiCallback callback) { + this.requestBody = requestBody; + this.callback = callback; + } + + @Override + public MediaType contentType() { + return requestBody.contentType(); + } + + @Override + public long contentLength() throws IOException { + return requestBody.contentLength(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + BufferedSink bufferedSink = Okio.buffer(sink(sink)); + requestBody.writeTo(bufferedSink); + bufferedSink.flush(); + } + + private Sink sink(Sink sink) { + return new ForwardingSink(sink) { + + long bytesWritten = 0L; + long contentLength = 0L; + + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + if (contentLength == 0) { + contentLength = contentLength(); + } + + bytesWritten += byteCount; + callback.onUploadProgress(bytesWritten, contentLength, bytesWritten == contentLength); + } + }; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressResponseBody.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressResponseBody.java new file mode 100644 index 00000000..2a70a020 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ProgressResponseBody.java @@ -0,0 +1,71 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import okhttp3.MediaType; +import okhttp3.ResponseBody; + +import java.io.IOException; + +import okio.Buffer; +import okio.BufferedSource; +import okio.ForwardingSource; +import okio.Okio; +import okio.Source; + +public class ProgressResponseBody extends ResponseBody { + + private final ResponseBody responseBody; + private final ApiCallback callback; + private BufferedSource bufferedSource; + + public ProgressResponseBody(ResponseBody responseBody, ApiCallback callback) { + this.responseBody = responseBody; + this.callback = callback; + } + + @Override + public MediaType contentType() { + return responseBody.contentType(); + } + + @Override + public long contentLength() { + return responseBody.contentLength(); + } + + @Override + public BufferedSource source() { + if (bufferedSource == null) { + bufferedSource = Okio.buffer(source(responseBody.source())); + } + return bufferedSource; + } + + private Source source(Source source) { + return new ForwardingSource(source) { + long totalBytesRead = 0L; + + @Override + public long read(Buffer sink, long byteCount) throws IOException { + long bytesRead = super.read(sink, byteCount); + // read() returns the number of bytes read, or -1 if this source is exhausted. + totalBytesRead += bytesRead != -1 ? bytesRead : 0; + callback.onDownloadProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1); + return bytesRead; + } + }; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerConfiguration.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerConfiguration.java new file mode 100644 index 00000000..a08edf73 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerConfiguration.java @@ -0,0 +1,73 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.Map; + +/** + * Representing a Server configuration. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServerConfiguration { + public String URL; + public String description; + public Map variables; + + /** + * @param URL A URL to the target host. + * @param description A description of the host designated by the URL. + * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template. + */ + public ServerConfiguration(String URL, String description, Map variables) { + this.URL = URL; + this.description = description; + this.variables = variables; + } + + /** + * Format URL template using given variables. + * + * @param variables A map between a variable name and its value. + * @return Formatted URL. + */ + public String URL(Map variables) { + String url = this.URL; + + // go through variables and replace placeholders + for (Map.Entry variable: this.variables.entrySet()) { + String name = variable.getKey(); + ServerVariable serverVariable = variable.getValue(); + String value = serverVariable.defaultValue; + + if (variables != null && variables.containsKey(name)) { + value = variables.get(name); + if (serverVariable.enumValues.size() > 0 && !serverVariable.enumValues.contains(value)) { + throw new IllegalArgumentException("The variable " + name + " in the server URL has invalid value " + value + "."); + } + } + url = url.replace("{" + name + "}", value); + } + return url; + } + + /** + * Format URL template using default server variables. + * + * @return Formatted URL. + */ + public String URL() { + return URL(null); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerVariable.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerVariable.java new file mode 100644 index 00000000..c1714708 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/ServerVariable.java @@ -0,0 +1,38 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.HashSet; + +/** + * Representing a Server Variable for server URL template substitution. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServerVariable { + public String description; + public String defaultValue; + public HashSet enumValues = null; + + /** + * @param description A description for the server variable. + * @param defaultValue The default value to use for substitution. + * @param enumValues An enumeration of string values to be used if the substitution options are from a limited set. + */ + public ServerVariable(String description, String defaultValue, HashSet enumValues) { + this.description = description; + this.defaultValue = defaultValue; + this.enumValues = enumValues; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/StringUtil.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/StringUtil.java new file mode 100644 index 00000000..53827943 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/StringUtil.java @@ -0,0 +1,84 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client; + +import java.util.Collection; +import java.util.Iterator; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class StringUtil { + /** + * Check if the given array contains the given value (with case-insensitive comparison). + * + * @param array The array + * @param value The value to search + * @return true if the array contains the value + */ + public static boolean containsIgnoreCase(String[] array, String value) { + for (String str : array) { + if (value == null && str == null) { + return true; + } + if (value != null && value.equalsIgnoreCase(str)) { + return true; + } + } + return false; + } + + /** + * Join an array of strings with the given separator. + *

+ * Note: This might be replaced by utility method from commons-lang or guava someday + * if one of those libraries is added as dependency. + *

+ * + * @param array The array of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(String[] array, String separator) { + int len = array.length; + if (len == 0) { + return ""; + } + + StringBuilder out = new StringBuilder(); + out.append(array[0]); + for (int i = 1; i < len; i++) { + out.append(separator).append(array[i]); + } + return out.toString(); + } + + /** + * Join a list of strings with the given separator. + * + * @param list The list of strings + * @param separator The separator + * @return the resulting string + */ + public static String join(Collection list, String separator) { + Iterator iterator = list.iterator(); + StringBuilder out = new StringBuilder(); + if (iterator.hasNext()) { + out.append(iterator.next()); + } + while (iterator.hasNext()) { + out.append(separator).append(iterator.next()); + } + return out.toString(); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java new file mode 100644 index 00000000..1340b987 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/ServiceApi.java @@ -0,0 +1,2629 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.api; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiCallback; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.Configuration; +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; +import eu.openanalytics.containerproxy.backend.spcs.client.ProgressRequestBody; +import eu.openanalytics.containerproxy.backend.spcs.client.ProgressResponseBody; + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + + +import eu.openanalytics.containerproxy.backend.spcs.client.model.ErrorResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.model.FetchServiceLogs200Response; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceEndpoint; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceInstance; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceRole; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceRoleGrantTo; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessAcceptedResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SuccessResponse; +import java.util.UUID; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ServiceApi { + private ApiClient localVarApiClient; + private int localHostIndex; + private String localCustomBaseUrl; + + public ServiceApi() { + this(Configuration.getDefaultApiClient()); + } + + public ServiceApi(ApiClient apiClient) { + this.localVarApiClient = apiClient; + } + + public ApiClient getApiClient() { + return localVarApiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.localVarApiClient = apiClient; + } + + public int getHostIndex() { + return localHostIndex; + } + + public void setHostIndex(int hostIndex) { + this.localHostIndex = hostIndex; + } + + public String getCustomBaseUrl() { + return localCustomBaseUrl; + } + + public void setCustomBaseUrl(String customBaseUrl) { + this.localCustomBaseUrl = customBaseUrl; + } + + /** + * Build call for createOrAlterService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param service (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call createOrAlterServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = service; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "PUT", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call createOrAlterServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling createOrAlterService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling createOrAlterService(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling createOrAlterService(Async)"); + } + + // verify the required parameter 'service' is set + if (service == null) { + throw new ApiException("Missing the required parameter 'service' when calling createOrAlterService(Async)"); + } + + return createOrAlterServiceCall(database, schema, name, service, _callback); + + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param service (required) + * @return SuccessResponse + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public SuccessResponse createOrAlterService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws ApiException { + ApiResponse localVarResp = createOrAlterServiceWithHttpInfo(database, schema, name, service); + return localVarResp.getData(); + } + + /** + * Create a (or alter an existing) service. + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param service (required) + * @return ApiResponse<SuccessResponse> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse createOrAlterServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service) throws ApiException { + okhttp3.Call localVarCall = createOrAlterServiceValidateBeforeCall(database, schema, name, service, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Create a (or alter an existing) service. (asynchronously) + * Create a (or alter an existing) service. Even if the operation is just an alter, the full property set must be provided. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param service (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call createOrAlterServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Service service, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = createOrAlterServiceValidateBeforeCall(database, schema, name, service, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for createService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service (required) + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. (optional, default to errorIfExists) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
408 Request Timeout. This indicates that the request from the client timed out and was not completed by the server. * X-Snowflake-Request-ID -
409 Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call createServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = service; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (createMode != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("createMode", createMode)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call createServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling createService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling createService(Async)"); + } + + // verify the required parameter 'service' is set + if (service == null) { + throw new ApiException("Missing the required parameter 'service' when calling createService(Async)"); + } + + return createServiceCall(database, schema, service, createMode, _callback); + + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service (required) + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. (optional, default to errorIfExists) + * @return SuccessResponse + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
408 Request Timeout. This indicates that the request from the client timed out and was not completed by the server. * X-Snowflake-Request-ID -
409 Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public SuccessResponse createService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws ApiException { + ApiResponse localVarResp = createServiceWithHttpInfo(database, schema, service, createMode); + return localVarResp.getData(); + } + + /** + * Create a service + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service (required) + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. (optional, default to errorIfExists) + * @return ApiResponse<SuccessResponse> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
408 Request Timeout. This indicates that the request from the client timed out and was not completed by the server. * X-Snowflake-Request-ID -
409 Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse createServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode) throws ApiException { + okhttp3.Call localVarCall = createServiceValidateBeforeCall(database, schema, service, createMode, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Create a service (asynchronously) + * Create a service, with standard create modifiers as query parameters. See the Service component definition for what is required to be provided in the request body. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service (required) + * @param createMode Query parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource. (optional, default to errorIfExists) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
408 Request Timeout. This indicates that the request from the client timed out and was not completed by the server. * X-Snowflake-Request-ID -
409 Conflict. The requested operation could not be performed due to a conflicting state that could not be resolved. This usually happens when a CREATE request was performed when there is a pre-existing resource with the same name, and also without one of the options orReplace/ifNotExists. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call createServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull Service service, @javax.annotation.Nullable String createMode, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = createServiceValidateBeforeCall(database, schema, service, createMode, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for deleteService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call deleteServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (ifExists != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("ifExists", ifExists)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "DELETE", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call deleteServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling deleteService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling deleteService(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling deleteService(Async)"); + } + + return deleteServiceCall(database, schema, name, ifExists, _callback); + + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return SuccessResponse + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public SuccessResponse deleteService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + ApiResponse localVarResp = deleteServiceWithHttpInfo(database, schema, name, ifExists); + return localVarResp.getData(); + } + + /** + * Delete a service + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return ApiResponse<SuccessResponse> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse deleteServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + okhttp3.Call localVarCall = deleteServiceValidateBeforeCall(database, schema, name, ifExists, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Delete a service (asynchronously) + * Delete a service with the given name. If ifExists is used, the operation will succeed even if the object does not exist. Otherwise, there will be a failure if the drop is unsuccessful. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call deleteServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = deleteServiceValidateBeforeCall(database, schema, name, ifExists, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for fetchService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call fetchServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call fetchServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling fetchService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling fetchService(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling fetchService(Async)"); + } + + return fetchServiceCall(database, schema, name, _callback); + + } + + /** + * + * Fetch a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return Service + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public Service fetchService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse localVarResp = fetchServiceWithHttpInfo(database, schema, name); + return localVarResp.getData(); + } + + /** + * + * Fetch a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<Service> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse fetchServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = fetchServiceValidateBeforeCall(database, schema, name, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * Fetch a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call fetchServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = fetchServiceValidateBeforeCall(database, schema, name, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for listServiceContainers + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceContainersCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}/containers" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call listServiceContainersValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling listServiceContainers(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling listServiceContainers(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling listServiceContainers(Async)"); + } + + return listServiceContainersCall(database, schema, name, _callback); + + } + + /** + * + * List all the containers of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return List<ServiceContainer> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List listServiceContainers(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse> localVarResp = listServiceContainersWithHttpInfo(database, schema, name); + return localVarResp.getData(); + } + + /** + * + * List all the containers of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<List<ServiceContainer>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> listServiceContainersWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = listServiceContainersValidateBeforeCall(database, schema, name, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * List all the containers of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceContainersAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = listServiceContainersValidateBeforeCall(database, schema, name, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for listServiceInstances + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceInstancesCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}/instances" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call listServiceInstancesValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling listServiceInstances(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling listServiceInstances(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling listServiceInstances(Async)"); + } + + return listServiceInstancesCall(database, schema, name, _callback); + + } + + /** + * + * List all the instances of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return List<ServiceInstance> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List listServiceInstances(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse> localVarResp = listServiceInstancesWithHttpInfo(database, schema, name); + return localVarResp.getData(); + } + + /** + * + * List all the instances of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<List<ServiceInstance>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> listServiceInstancesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = listServiceInstancesValidateBeforeCall(database, schema, name, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * List all the instances of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceInstancesAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = listServiceInstancesValidateBeforeCall(database, schema, name, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for listServiceRoleGrantsTo + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service Name of the service that contains the service role. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceRoleGrantsToCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{service}/roles/{name}/grants" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "service" + "}", localVarApiClient.escapeString(service.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call listServiceRoleGrantsToValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling listServiceRoleGrantsTo(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling listServiceRoleGrantsTo(Async)"); + } + + // verify the required parameter 'service' is set + if (service == null) { + throw new ApiException("Missing the required parameter 'service' when calling listServiceRoleGrantsTo(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling listServiceRoleGrantsTo(Async)"); + } + + return listServiceRoleGrantsToCall(database, schema, service, name, _callback); + + } + + /** + * + * List all the grants given to the service role + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service Name of the service that contains the service role. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return List<ServiceRoleGrantTo> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List listServiceRoleGrantsTo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse> localVarResp = listServiceRoleGrantsToWithHttpInfo(database, schema, service, name); + return localVarResp.getData(); + } + + /** + * + * List all the grants given to the service role + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service Name of the service that contains the service role. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<List<ServiceRoleGrantTo>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> listServiceRoleGrantsToWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = listServiceRoleGrantsToValidateBeforeCall(database, schema, service, name, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * List all the grants given to the service role + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param service Name of the service that contains the service role. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceRoleGrantsToAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String service, @javax.annotation.Nonnull String name, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = listServiceRoleGrantsToValidateBeforeCall(database, schema, service, name, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for listServiceRoles + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceRolesCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}/roles" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call listServiceRolesValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling listServiceRoles(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling listServiceRoles(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling listServiceRoles(Async)"); + } + + return listServiceRolesCall(database, schema, name, _callback); + + } + + /** + * + * List all the service roles of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return List<ServiceRole> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List listServiceRoles(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse> localVarResp = listServiceRolesWithHttpInfo(database, schema, name); + return localVarResp.getData(); + } + + /** + * + * List all the service roles of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<List<ServiceRole>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> listServiceRolesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = listServiceRolesValidateBeforeCall(database, schema, name, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * List all the service roles of the service + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServiceRolesAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = listServiceRolesValidateBeforeCall(database, schema, name, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for listServices + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. (optional) + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. (optional) + * @param showLimit Parameter to limit the maximum number of rows returned by a command. (optional) + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. (optional) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServicesCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (like != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("like", like)); + } + + if (startsWith != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("startsWith", startsWith)); + } + + if (showLimit != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("showLimit", showLimit)); + } + + if (fromName != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("fromName", fromName)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call listServicesValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling listServices(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling listServices(Async)"); + } + + return listServicesCall(database, schema, like, startsWith, showLimit, fromName, _callback); + + } + + /** + * List services + * Lists the services under the database and schema. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. (optional) + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. (optional) + * @param showLimit Parameter to limit the maximum number of rows returned by a command. (optional) + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. (optional) + * @return List<Service> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List listServices(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws ApiException { + ApiResponse> localVarResp = listServicesWithHttpInfo(database, schema, like, startsWith, showLimit, fromName); + return localVarResp.getData(); + } + + /** + * List services + * Lists the services under the database and schema. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. (optional) + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. (optional) + * @param showLimit Parameter to limit the maximum number of rows returned by a command. (optional) + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. (optional) + * @return ApiResponse<List<Service>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> listServicesWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName) throws ApiException { + okhttp3.Call localVarCall = listServicesValidateBeforeCall(database, schema, like, startsWith, showLimit, fromName, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * List services (asynchronously) + * Lists the services under the database and schema. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param like Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters. (optional) + * @param startsWith Parameter to filter the command output based on the string of characters that appear at the beginning of the object name. Uses case-sensitive pattern matching. (optional) + * @param showLimit Parameter to limit the maximum number of rows returned by a command. (optional) + * @param fromName Parameter to enable fetching rows only following the first row whose object name matches the specified string. Case-sensitive and does not have to be the full name. (optional) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call listServicesAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nullable String like, @javax.annotation.Nullable String startsWith, @javax.annotation.Nullable Integer showLimit, @javax.annotation.Nullable String fromName, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = listServicesValidateBeforeCall(database, schema, like, startsWith, showLimit, fromName, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for resumeService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call resumeServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}:resume" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (ifExists != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("ifExists", ifExists)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call resumeServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling resumeService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling resumeService(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling resumeService(Async)"); + } + + return resumeServiceCall(database, schema, name, ifExists, _callback); + + } + + /** + * + * Resume a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return SuccessResponse + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public SuccessResponse resumeService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + ApiResponse localVarResp = resumeServiceWithHttpInfo(database, schema, name, ifExists); + return localVarResp.getData(); + } + + /** + * + * Resume a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return ApiResponse<SuccessResponse> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse resumeServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + okhttp3.Call localVarCall = resumeServiceValidateBeforeCall(database, schema, name, ifExists, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * Resume a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call resumeServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = resumeServiceValidateBeforeCall(database, schema, name, ifExists, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for showServiceEndpoints + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call showServiceEndpointsCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}/endpoints" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call showServiceEndpointsValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling showServiceEndpoints(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling showServiceEndpoints(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling showServiceEndpoints(Async)"); + } + + return showServiceEndpointsCall(database, schema, name, _callback); + + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return List<ServiceEndpoint> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public List showServiceEndpoints(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + ApiResponse> localVarResp = showServiceEndpointsWithHttpInfo(database, schema, name); + return localVarResp.getData(); + } + + /** + * List the endpoints in a service. + * Lists the endpoints in a Snowpark Container Services service (or a job service). + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @return ApiResponse<List<ServiceEndpoint>> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse> showServiceEndpointsWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name) throws ApiException { + okhttp3.Call localVarCall = showServiceEndpointsValidateBeforeCall(database, schema, name, null); + Type localVarReturnType = new TypeToken>(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * List the endpoints in a service. (asynchronously) + * Lists the endpoints in a Snowpark Container Services service (or a job service). + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call showServiceEndpointsAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, final ApiCallback> _callback) throws ApiException { + + okhttp3.Call localVarCall = showServiceEndpointsValidateBeforeCall(database, schema, name, _callback); + Type localVarReturnType = new TypeToken>(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for suspendService + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call suspendServiceCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}:suspend" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (ifExists != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("ifExists", ifExists)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call suspendServiceValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling suspendService(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling suspendService(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling suspendService(Async)"); + } + + return suspendServiceCall(database, schema, name, ifExists, _callback); + + } + + /** + * + * Suspend a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return SuccessResponse + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public SuccessResponse suspendService(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + ApiResponse localVarResp = suspendServiceWithHttpInfo(database, schema, name, ifExists); + return localVarResp.getData(); + } + + /** + * + * Suspend a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @return ApiResponse<SuccessResponse> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse suspendServiceWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists) throws ApiException { + okhttp3.Call localVarCall = suspendServiceValidateBeforeCall(database, schema, name, ifExists, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * Suspend a service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param ifExists Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist. (optional, default to false) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 Successful request. * X-Snowflake-Request-ID -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call suspendServiceAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nullable Boolean ifExists, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = suspendServiceValidateBeforeCall(database, schema, name, ifExists, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for fetchServiceLogs + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param instanceId ID of the service instance, starting with 0. (required) + * @param containerName Container name as specified in the service specification file. (required) + * @param numLines Number of trailing log lines to retrieve. (optional) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call fetchServiceLogsCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/databases/{database}/schemas/{schema}/services/{name}/logs" + .replace("{" + "database" + "}", localVarApiClient.escapeString(database.toString())) + .replace("{" + "schema" + "}", localVarApiClient.escapeString(schema.toString())) + .replace("{" + "name" + "}", localVarApiClient.escapeString(name.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (instanceId != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("instanceId", instanceId)); + } + + if (containerName != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("containerName", containerName)); + } + + if (numLines != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("numLines", numLines)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "ExternalOAuth", "KeyPair", "SnowflakeOAuth" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call fetchServiceLogsValidateBeforeCall(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'database' is set + if (database == null) { + throw new ApiException("Missing the required parameter 'database' when calling fetchServiceLogs(Async)"); + } + + // verify the required parameter 'schema' is set + if (schema == null) { + throw new ApiException("Missing the required parameter 'schema' when calling fetchServiceLogs(Async)"); + } + + // verify the required parameter 'name' is set + if (name == null) { + throw new ApiException("Missing the required parameter 'name' when calling fetchServiceLogs(Async)"); + } + + // verify the required parameter 'instanceId' is set + if (instanceId == null) { + throw new ApiException("Missing the required parameter 'instanceId' when calling fetchServiceLogs(Async)"); + } + + // verify the required parameter 'containerName' is set + if (containerName == null) { + throw new ApiException("Missing the required parameter 'containerName' when calling fetchServiceLogs(Async)"); + } + + return fetchServiceLogsCall(database, schema, name, instanceId, containerName, numLines, _callback); + + } + + /** + * + * Fetch the logs for a given service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param instanceId ID of the service instance, starting with 0. (required) + * @param containerName Container name as specified in the service specification file. (required) + * @param numLines Number of trailing log lines to retrieve. (optional) + * @return FetchServiceLogs200Response + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public FetchServiceLogs200Response fetchServiceLogs(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws ApiException { + ApiResponse localVarResp = fetchServiceLogsWithHttpInfo(database, schema, name, instanceId, containerName, numLines); + return localVarResp.getData(); + } + + /** + * + * Fetch the logs for a given service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param instanceId ID of the service instance, starting with 0. (required) + * @param containerName Container name as specified in the service specification file. (required) + * @param numLines Number of trailing log lines to retrieve. (optional) + * @return ApiResponse<FetchServiceLogs200Response> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public ApiResponse fetchServiceLogsWithHttpInfo(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines) throws ApiException { + okhttp3.Call localVarCall = fetchServiceLogsValidateBeforeCall(database, schema, name, instanceId, containerName, numLines, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * (asynchronously) + * Fetch the logs for a given service. + * @param database Identifier (i.e. name) for the database to which the resource belongs. You can use the `/api/v2/databases` GET request to get a list of available databases. (required) + * @param schema Identifier (i.e. name) for the schema to which the resource belongs. You can use the `/api/v2/databases/{database}/schemas` GET request to get a list of available schemas for the specified database. (required) + * @param name Identifier (i.e. name) for the resource. (required) + * @param instanceId ID of the service instance, starting with 0. (required) + * @param containerName Container name as specified in the service specification file. (required) + * @param numLines Number of trailing log lines to retrieve. (optional) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 successful * X-Snowflake-Request-ID -
* Link -
202 Successfully accepted the request, but it is not completed yet. * Location -
* X-Snowflake-Request-ID -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. * X-Snowflake-Request-ID -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. * X-Snowflake-Request-ID -
403 Forbidden. The request is forbidden. This can also happen if the request is made even if the API is not enabled. * X-Snowflake-Request-ID -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint does not exist, or if the API is not enabled. * X-Snowflake-Request-ID -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. * X-Snowflake-Request-ID -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. * X-Snowflake-Request-ID -
500 Internal Server Error. The server hit an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. * X-Snowflake-Request-ID -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. * X-Snowflake-Request-ID -
+ */ + public okhttp3.Call fetchServiceLogsAsync(@javax.annotation.Nonnull String database, @javax.annotation.Nonnull String schema, @javax.annotation.Nonnull String name, @javax.annotation.Nonnull Integer instanceId, @javax.annotation.Nonnull String containerName, @javax.annotation.Nullable Integer numLines, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = fetchServiceLogsValidateBeforeCall(database, schema, name, instanceId, containerName, numLines, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java new file mode 100644 index 00000000..da3ac030 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/api/StatementsApi.java @@ -0,0 +1,744 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.api; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiCallback; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiResponse; +import eu.openanalytics.containerproxy.backend.spcs.client.Configuration; +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; +import eu.openanalytics.containerproxy.backend.spcs.client.ProgressRequestBody; +import eu.openanalytics.containerproxy.backend.spcs.client.ProgressResponseBody; + +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; + + +import eu.openanalytics.containerproxy.backend.spcs.client.model.CancelStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.QueryFailureStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.QueryStatus; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSet; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequest; +import java.util.UUID; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class StatementsApi { + private ApiClient localVarApiClient; + private int localHostIndex; + private String localCustomBaseUrl; + + public StatementsApi() { + this(Configuration.getDefaultApiClient()); + } + + public StatementsApi(ApiClient apiClient) { + this.localVarApiClient = apiClient; + } + + public ApiClient getApiClient() { + return localVarApiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.localVarApiClient = apiClient; + } + + public int getHostIndex() { + return localHostIndex; + } + + public void setHostIndex(int hostIndex) { + this.localHostIndex = hostIndex; + } + + public String getCustomBaseUrl() { + return localCustomBaseUrl; + } + + public void setCustomBaseUrl(String customBaseUrl) { + this.localCustomBaseUrl = customBaseUrl; + } + + /** + * Build call for cancelStatement + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The execution of the statement was successfully canceled. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
422 An error occurred when cancelling the execution of the statement. Check the error code and error message for details. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call cancelStatementCall(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/statements/{statementHandle}/cancel" + .replace("{" + "statementHandle" + "}", localVarApiClient.escapeString(statementHandle.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (requestId != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("requestId", requestId)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + if (accept != null) { + localVarHeaderParams.put("Accept", localVarApiClient.parameterToString(accept)); + } + + + if (userAgent != null) { + localVarHeaderParams.put("User-Agent", localVarApiClient.parameterToString(userAgent)); + } + + + if (xSnowflakeAuthorizationTokenType != null) { + localVarHeaderParams.put("X-Snowflake-Authorization-Token-Type", localVarApiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + } + + + // BUG in auto generated code: "snowflakeOAuth" should be "SnowflakeOAuth", "keyPair" should be "KeyPair" + String[] localVarAuthNames = new String[] { "ExternalOAuth", "SnowflakeOAuth", "KeyPair" }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call cancelStatementValidateBeforeCall(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'statementHandle' is set + if (statementHandle == null) { + throw new ApiException("Missing the required parameter 'statementHandle' when calling cancelStatement(Async)"); + } + + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new ApiException("Missing the required parameter 'userAgent' when calling cancelStatement(Async)"); + } + + return cancelStatementCall(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType, _callback); + + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return CancelStatus + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The execution of the statement was successfully canceled. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
422 An error occurred when cancelling the execution of the statement. Check the error code and error message for details. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public CancelStatus cancelStatement(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + ApiResponse localVarResp = cancelStatementWithHttpInfo(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType); + return localVarResp.getData(); + } + + /** + * Cancels the execution of a statement. + * Cancels the execution of the statement with the specified statement handle. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return ApiResponse<CancelStatus> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The execution of the statement was successfully canceled. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
422 An error occurred when cancelling the execution of the statement. Check the error code and error message for details. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public ApiResponse cancelStatementWithHttpInfo(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + okhttp3.Call localVarCall = cancelStatementValidateBeforeCall(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Cancels the execution of a statement. (asynchronously) + * Cancels the execution of the statement with the specified statement handle. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The execution of the statement was successfully canceled. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
422 An error occurred when cancelling the execution of the statement. Check the error code and error message for details. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call cancelStatementAsync(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = cancelStatementValidateBeforeCall(statementHandle, userAgent, requestId, accept, xSnowflakeAuthorizationTokenType, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for getStatementStatus + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use this method again to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call getStatementStatusCall(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/api/v2/statements/{statementHandle}" + .replace("{" + "statementHandle" + "}", localVarApiClient.escapeString(statementHandle.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (requestId != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("requestId", requestId)); + } + + if (partition != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("partition", partition)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + if (accept != null) { + localVarHeaderParams.put("Accept", localVarApiClient.parameterToString(accept)); + } + + + if (userAgent != null) { + localVarHeaderParams.put("User-Agent", localVarApiClient.parameterToString(userAgent)); + } + + + if (xSnowflakeAuthorizationTokenType != null) { + localVarHeaderParams.put("X-Snowflake-Authorization-Token-Type", localVarApiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + } + + + // BUG in auto generated code: "snowflakeOAuth" should be "SnowflakeOAuth", "keyPair" should be "KeyPair" + String[] localVarAuthNames = new String[] { "ExternalOAuth", "SnowflakeOAuth", "KeyPair" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call getStatementStatusValidateBeforeCall(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'statementHandle' is set + if (statementHandle == null) { + throw new ApiException("Missing the required parameter 'statementHandle' when calling getStatementStatus(Async)"); + } + + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new ApiException("Missing the required parameter 'userAgent' when calling getStatementStatus(Async)"); + } + + return getStatementStatusCall(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType, _callback); + + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return ResultSet + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use this method again to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public ResultSet getStatementStatus(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + ApiResponse localVarResp = getStatementStatusWithHttpInfo(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType); + return localVarResp.getData(); + } + + /** + * Checks the status of the execution of a statement + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return ApiResponse<ResultSet> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use this method again to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public ApiResponse getStatementStatusWithHttpInfo(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + okhttp3.Call localVarCall = getStatementStatusValidateBeforeCall(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Checks the status of the execution of a statement (asynchronously) + * Checks the status of the execution of the statement with the specified statement handle. If the statement was executed successfully, the operation returns the requested partition of the result set. + * @param statementHandle The handle of the statement that you want to use (e.g. to fetch the result set or cancel execution). (required) + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param partition Number of the partition of results to return. The number can range from 0 to the total number of partitions minus 1. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use this method again to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call getStatementStatusAsync(@javax.annotation.Nonnull UUID statementHandle, @javax.annotation.Nonnull String userAgent, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Long partition, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = getStatementStatusValidateBeforeCall(statementHandle, userAgent, requestId, partition, accept, xSnowflakeAuthorizationTokenType, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + /** + * Build call for submitStatement + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. (optional) + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback Callback for upload/download progress + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
408 The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call submitStatementCall(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = submitStatementRequest; + + // create path and map variables + String localVarPath = "/api/v2/statements"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + if (requestId != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("requestId", requestId)); + } + + if (async != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("async", async)); + } + + if (nullable != null) { + localVarQueryParams.addAll(localVarApiClient.parameterToPair("nullable", nullable)); + } + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + if (accept != null) { + localVarHeaderParams.put("Accept", localVarApiClient.parameterToString(accept)); + } + + + if (userAgent != null) { + localVarHeaderParams.put("User-Agent", localVarApiClient.parameterToString(userAgent)); + } + + + if (xSnowflakeAuthorizationTokenType != null) { + localVarHeaderParams.put("X-Snowflake-Authorization-Token-Type", localVarApiClient.parameterToString(xSnowflakeAuthorizationTokenType)); + } + + + // BUG in auto generated code: "snowflakeOAuth" should be "SnowflakeOAuth", "keyPair" should be "KeyPair" + String[] localVarAuthNames = new String[] { "ExternalOAuth", "SnowflakeOAuth", "KeyPair" }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call submitStatementValidateBeforeCall(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'userAgent' is set + if (userAgent == null) { + throw new ApiException("Missing the required parameter 'userAgent' when calling submitStatement(Async)"); + } + + // verify the required parameter 'submitStatementRequest' is set + if (submitStatementRequest == null) { + throw new ApiException("Missing the required parameter 'submitStatementRequest' when calling submitStatement(Async)"); + } + + return submitStatementCall(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType, _callback); + + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. (optional) + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return ResultSet + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
408 The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public ResultSet submitStatement(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + ApiResponse localVarResp = submitStatementWithHttpInfo(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType); + return localVarResp.getData(); + } + + /** + * Submits a SQL statement for execution. + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. (optional) + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @return ApiResponse<ResultSet> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
408 The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public ApiResponse submitStatementWithHttpInfo(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType) throws ApiException { + okhttp3.Call localVarCall = submitStatementValidateBeforeCall(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + /** + * Submits a SQL statement for execution. (asynchronously) + * Submits one or more statements for execution. You can specify that the statement should be executed asynchronously. + * @param userAgent Set this to the name and version of your application (e.g. “applicationName/applicationVersion”). You must use a value that complies with RFC 7231. (required) + * @param submitStatementRequest Specifies the SQL statement to execute and the statement context. (required) + * @param requestId Unique ID of the API request. This ensures that the execution is idempotent. If not specified, a new UUID is generated and assigned. (optional) + * @param async Set to true to execute the statement asynchronously and return the statement handle. If the parameter is not specified or is set to false, a statement is executed and the first result is returned if the execution is completed in 45 seconds. If the statement execution takes longer to complete, the statement handle is returned. (optional) + * @param nullable Set to true to execute the statement to generate the result set including null. If the parameter is set to false, the result set value null will be replaced with a string 'null'. (optional) + * @param accept The response payload format. The schema should be specified in resultSetMetaData in the request payload. (optional) + * @param xSnowflakeAuthorizationTokenType Specify the authorization token type for the Authorization header. KEYPAIR_JWT is for Keypair JWT or OAUTH for oAuth token. If not specified, OAUTH is assumed. (optional) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + + + + + + + + + + +
Response Details
Status Code Description Response Headers
200 The statement was executed successfully, and the response includes any data requested. * link -
202 The execution of the statement is still in progress. Use GET /statements/ and specify the statement handle to check the status of the statement execution. -
400 Bad Request. The request payload is invalid or malformed. This happens if the application didn't send the correct request payload. The response body may include the error code and message indicating the actual cause. The application must reconstruct the request body for retry. -
401 Unauthorized. The request is not authorized. This happens if the attached access token is invalid or missing. The response body may include the error code and message indicating the actual cause, e.g., expired, invalid token. The application must obtain a new access token for retry. -
403 Forbidden. The request is forbidden. This happens if the request is made even if the API is not enabled. -
404 Not Found. The request endpoint is not valid. This happens if the API endpoint is wrong. For example, if the application hits /api/api/hello which doesn't exist, it will receive this code. -
405 Method Not Allowed. The request method doesn't match the supported API. This happens, for example, if the application calls the API with GET method but the endpoint accepts only POST. The application must change a method for retry. -
408 The execution of the statement exceeded the timeout period. The execution of the statement was cancelled. -
415 The request header Content-Type includes unsupported media type. The API supports application/json only. If none specified, the request payload is taken as JSON, but if any other media type is specified, this error is returned. -
422 An error occurred when executing the statement. Check the error code and error message for details. -
429 Limit Exceeded. The number of requests hit the rate limit. The application must slow down the frequency of hitting the API endpoints. -
500 Internal Server Error. The server hits an unrecoverable system error. The response body may include the error code and message for further guidance. The application owner may need to reach out the customer support. -
503 Service Unavailable. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
504 Gateway Timeout. The request was not processed due to server side timeouts. The application may retry with backoff. The jittered backoff is recommended. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ -
+ */ + public okhttp3.Call submitStatementAsync(@javax.annotation.Nonnull String userAgent, @javax.annotation.Nonnull SubmitStatementRequest submitStatementRequest, @javax.annotation.Nullable UUID requestId, @javax.annotation.Nullable Boolean async, @javax.annotation.Nullable Boolean nullable, @javax.annotation.Nullable String accept, @javax.annotation.Nullable String xSnowflakeAuthorizationTokenType, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = submitStatementValidateBeforeCall(userAgent, submitStatementRequest, requestId, async, nullable, accept, xSnowflakeAuthorizationTokenType, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } +} diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java new file mode 100644 index 00000000..30e674b1 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/ApiKeyAuth.java @@ -0,0 +1,81 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; + +import java.net.URI; +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ApiKeyAuth implements Authentication { + private final String location; + private final String paramName; + + private String apiKey; + private String apiKeyPrefix; + + public ApiKeyAuth(String location, String paramName) { + this.location = location; + this.paramName = paramName; + } + + public String getLocation() { + return location; + } + + public String getParamName() { + return paramName; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getApiKeyPrefix() { + return apiKeyPrefix; + } + + public void setApiKeyPrefix(String apiKeyPrefix) { + this.apiKeyPrefix = apiKeyPrefix; + } + + @Override + public void applyToParams(List queryParams, Map headerParams, Map cookieParams, + String payload, String method, URI uri) throws ApiException { + if (apiKey == null) { + return; + } + String value; + if (apiKeyPrefix != null) { + value = apiKeyPrefix + " " + apiKey; + } else { + value = apiKey; + } + if ("query".equals(location)) { + queryParams.add(new Pair(paramName, value)); + } else if ("header".equals(location)) { + headerParams.put(paramName, value); + } else if ("cookie".equals(location)) { + cookieParams.put(paramName, value); + } + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java new file mode 100644 index 00000000..49c4c831 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/Authentication.java @@ -0,0 +1,38 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; + +import java.net.URI; +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public interface Authentication { + /** + * Apply authentication settings to header and query params. + * + * @param queryParams List of query parameters + * @param headerParams Map of header parameters + * @param cookieParams Map of cookie parameters + * @param payload HTTP request body + * @param method HTTP method + * @param uri URI + * @throws ApiException if failed to update the parameters + */ + void applyToParams(List queryParams, Map headerParams, Map cookieParams, String payload, String method, URI uri) throws ApiException; +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java new file mode 100644 index 00000000..b718c213 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBasicAuth.java @@ -0,0 +1,56 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; + +import okhttp3.Credentials; + +import java.net.URI; +import java.util.Map; +import java.util.List; + +public class HttpBasicAuth implements Authentication { + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public void applyToParams(List queryParams, Map headerParams, Map cookieParams, + String payload, String method, URI uri) throws ApiException { + if (username == null && password == null) { + return; + } + headerParams.put("Authorization", Credentials.basic( + username == null ? "" : username, + password == null ? "" : password)); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java new file mode 100644 index 00000000..f53d2bf2 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/HttpBearerAuth.java @@ -0,0 +1,76 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; + +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class HttpBearerAuth implements Authentication { + private final String scheme; + private Supplier tokenSupplier; + + public HttpBearerAuth(String scheme) { + this.scheme = scheme; + } + + /** + * Gets the token, which together with the scheme, will be sent as the value of the Authorization header. + * + * @return The bearer token + */ + public String getBearerToken() { + return tokenSupplier.get(); + } + + /** + * Sets the token, which together with the scheme, will be sent as the value of the Authorization header. + * + * @param bearerToken The bearer token to send in the Authorization header + */ + public void setBearerToken(String bearerToken) { + this.tokenSupplier = () -> bearerToken; + } + + /** + * Sets the supplier of tokens, which together with the scheme, will be sent as the value of the Authorization header. + * + * @param tokenSupplier The supplier of bearer tokens to send in the Authorization header + */ + public void setBearerToken(Supplier tokenSupplier) { + this.tokenSupplier = tokenSupplier; + } + + @Override + public void applyToParams(List queryParams, Map headerParams, Map cookieParams, + String payload, String method, URI uri) throws ApiException { + String bearerToken = Optional.ofNullable(tokenSupplier).map(Supplier::get).orElse(null); + if (bearerToken == null) { + return; + } + + headerParams.put("Authorization", (scheme != null ? upperCaseBearer(scheme) + " " : "") + bearerToken); + } + + private static String upperCaseBearer(String scheme) { + return ("bearer".equalsIgnoreCase(scheme)) ? "Bearer" : scheme; + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java new file mode 100644 index 00000000..0ef1f203 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuth.java @@ -0,0 +1,43 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; + +import java.net.URI; +import java.util.Map; +import java.util.List; + +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class OAuth implements Authentication { + private String accessToken; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public void applyToParams(List queryParams, Map headerParams, Map cookieParams, + String payload, String method, URI uri) throws ApiException { + if (accessToken != null) { + headerParams.put("Authorization", "Bearer " + accessToken); + } + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthFlow.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthFlow.java new file mode 100644 index 00000000..54394928 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthFlow.java @@ -0,0 +1,26 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +/** + * OAuth flows that are supported by this client + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public enum OAuthFlow { + ACCESS_CODE, //called authorizationCode in OpenAPI 3.0 + IMPLICIT, + PASSWORD, + APPLICATION //called clientCredentials in OpenAPI 3.0 +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthOkHttpClient.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthOkHttpClient.java new file mode 100644 index 00000000..07fc2357 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/OAuthOkHttpClient.java @@ -0,0 +1,83 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import okhttp3.OkHttpClient; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +import org.apache.oltu.oauth2.client.HttpClient; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.response.OAuthClientResponse; +import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; + +public class OAuthOkHttpClient implements HttpClient { + private OkHttpClient client; + + public OAuthOkHttpClient() { + this.client = new OkHttpClient(); + } + + public OAuthOkHttpClient(OkHttpClient client) { + this.client = client; + } + + @Override + public T execute(OAuthClientRequest request, Map headers, + String requestMethod, Class responseClass) + throws OAuthSystemException, OAuthProblemException { + + MediaType mediaType = MediaType.parse("application/json"); + Request.Builder requestBuilder = new Request.Builder().url(request.getLocationUri()); + + if(headers != null) { + for (Entry entry : headers.entrySet()) { + if (entry.getKey().equalsIgnoreCase("Content-Type")) { + mediaType = MediaType.parse(entry.getValue()); + } else { + requestBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + } + + RequestBody body = request.getBody() != null ? RequestBody.create(request.getBody(), mediaType) : null; + requestBuilder.method(requestMethod, body); + + try { + Response response = client.newCall(requestBuilder.build()).execute(); + return OAuthClientResponseFactory.createCustomResponse( + response.body().string(), + response.body().contentType().toString(), + response.code(), + response.headers().toMultimap(), + responseClass); + } catch (IOException e) { + throw new OAuthSystemException(e); + } + } + + @Override + public void shutdown() { + // Nothing to do here + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/RetryingOAuth.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/RetryingOAuth.java new file mode 100644 index 00000000..d4d5dc73 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/auth/RetryingOAuth.java @@ -0,0 +1,224 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.auth; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.Pair; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import org.apache.oltu.oauth2.client.OAuthClient; +import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; +import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.apache.oltu.oauth2.common.message.types.GrantType; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.Map; +import java.util.List; + +public class RetryingOAuth extends OAuth implements Interceptor { + private OAuthClient oAuthClient; + + private TokenRequestBuilder tokenRequestBuilder; + + /** + * @param client An OkHttp client + * @param tokenRequestBuilder A token request builder + */ + public RetryingOAuth(OkHttpClient client, TokenRequestBuilder tokenRequestBuilder) { + this.oAuthClient = new OAuthClient(new OAuthOkHttpClient(client)); + this.tokenRequestBuilder = tokenRequestBuilder; + } + + /** + * @param tokenRequestBuilder A token request builder + */ + public RetryingOAuth(TokenRequestBuilder tokenRequestBuilder) { + this(new OkHttpClient(), tokenRequestBuilder); + } + + /** + * @param tokenUrl The token URL to be used for this OAuth2 flow. + * Applicable to the following OAuth2 flows: "password", "clientCredentials" and "authorizationCode". + * The value must be an absolute URL. + * @param clientId The OAuth2 client ID for the "clientCredentials" flow. + * @param flow OAuth flow. + * @param clientSecret The OAuth2 client secret for the "clientCredentials" flow. + * @param parameters A map of string. + */ + public RetryingOAuth( + String tokenUrl, + String clientId, + OAuthFlow flow, + String clientSecret, + Map parameters + ) { + this(OAuthClientRequest.tokenLocation(tokenUrl) + .setClientId(clientId) + .setClientSecret(clientSecret)); + setFlow(flow); + if (parameters != null) { + for (Map.Entry entry : parameters.entrySet()) { + tokenRequestBuilder.setParameter(entry.getKey(), entry.getValue()); + } + } + } + + /** + * Set the OAuth flow + * + * @param flow The OAuth flow. + */ + public void setFlow(OAuthFlow flow) { + switch(flow) { + case ACCESS_CODE: + tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE); + break; + case IMPLICIT: + tokenRequestBuilder.setGrantType(GrantType.IMPLICIT); + break; + case PASSWORD: + tokenRequestBuilder.setGrantType(GrantType.PASSWORD); + break; + case APPLICATION: + tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS); + break; + default: + break; + } + } + + @Override + public Response intercept(Chain chain) throws IOException { + return retryingIntercept(chain, true); + } + + private Response retryingIntercept(Chain chain, boolean updateTokenAndRetryOnAuthorizationFailure) throws IOException { + Request request = chain.request(); + + // If the request already has an authorization (e.g. Basic auth), proceed with the request as is + if (request.header("Authorization") != null) { + return chain.proceed(request); + } + + // Get the token if it has not yet been acquired + if (getAccessToken() == null) { + updateAccessToken(null); + } + + OAuthClientRequest oAuthRequest; + if (getAccessToken() != null) { + // Build the request + Request.Builder requestBuilder = request.newBuilder(); + + String requestAccessToken = getAccessToken(); + try { + oAuthRequest = + new OAuthBearerClientRequest(request.url().toString()). + setAccessToken(requestAccessToken). + buildHeaderMessage(); + } catch (OAuthSystemException e) { + throw new IOException(e); + } + + Map headers = oAuthRequest.getHeaders(); + for (Map.Entry entry : headers.entrySet()) { + requestBuilder.addHeader(entry.getKey(), entry.getValue()); + } + requestBuilder.url(oAuthRequest.getLocationUri()); + + // Execute the request + Response response = chain.proceed(requestBuilder.build()); + + // 401/403 response codes most likely indicate an expired access token, unless it happens two times in a row + if ( + response != null && + ( response.code() == HttpURLConnection.HTTP_UNAUTHORIZED || + response.code() == HttpURLConnection.HTTP_FORBIDDEN ) && + updateTokenAndRetryOnAuthorizationFailure + ) { + try { + if (updateAccessToken(requestAccessToken)) { + response.body().close(); + return retryingIntercept(chain, false); + } + } catch (Exception e) { + response.body().close(); + throw e; + } + } + return response; + } + else { + return chain.proceed(chain.request()); + } + } + + /** + * Returns true if the access token has been updated + * + * @param requestAccessToken the request access token + * @return True if the update is successful + * @throws java.io.IOException If fail to update the access token + */ + public synchronized boolean updateAccessToken(String requestAccessToken) throws IOException { + if (getAccessToken() == null || getAccessToken().equals(requestAccessToken)) { + try { + OAuthJSONAccessTokenResponse accessTokenResponse = + oAuthClient.accessToken(tokenRequestBuilder.buildBodyMessage()); + if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) { + setAccessToken(accessTokenResponse.getAccessToken()); + } + } catch (OAuthSystemException | OAuthProblemException e) { + throw new IOException(e); + } + } + return getAccessToken() == null || !getAccessToken().equals(requestAccessToken); + } + + /** + * Gets the token request builder + * + * @return A token request builder + */ + public TokenRequestBuilder getTokenRequestBuilder() { + return tokenRequestBuilder; + } + + /** + * Sets the token request builder + * + * @param tokenRequestBuilder Token request builder + */ + public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { + this.tokenRequestBuilder = tokenRequestBuilder; + } + + // Applying authorization to parameters is performed in the retryingIntercept method + @Override + public void applyToParams(List queryParams, Map headerParams, Map cookieParams, + String payload, String method, URI uri) throws ApiException { + // No implementation necessary + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/AbstractOpenApiSchema.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/AbstractOpenApiSchema.java new file mode 100644 index 00000000..3f3490b7 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/AbstractOpenApiSchema.java @@ -0,0 +1,147 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import java.util.Objects; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * Abstract class for oneOf,anyOf schemas defined in OpenAPI spec + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public abstract class AbstractOpenApiSchema { + + // store the actual instance of the schema/object + private Object instance; + + // is nullable + private Boolean isNullable; + + // schema type (e.g. oneOf, anyOf) + private final String schemaType; + + public AbstractOpenApiSchema(String schemaType, Boolean isNullable) { + this.schemaType = schemaType; + this.isNullable = isNullable; + } + + /** + * Get the list of oneOf/anyOf composed schemas allowed to be stored in this object + * + * @return an instance of the actual schema/object + */ + public abstract Map> getSchemas(); + + /** + * Get the actual instance + * + * @return an instance of the actual schema/object + */ + //@JsonValue + public Object getActualInstance() {return instance;} + + /** + * Set the actual instance + * + * @param instance the actual instance of the schema/object + */ + public void setActualInstance(Object instance) {this.instance = instance;} + + /** + * Get the instant recursively when the schemas defined in oneOf/anyof happen to be oneOf/anyOf schema as well + * + * @return an instance of the actual schema/object + */ + public Object getActualInstanceRecursively() { + return getActualInstanceRecursively(this); + } + + private Object getActualInstanceRecursively(AbstractOpenApiSchema object) { + if (object.getActualInstance() == null) { + return null; + } else if (object.getActualInstance() instanceof AbstractOpenApiSchema) { + return getActualInstanceRecursively((AbstractOpenApiSchema)object.getActualInstance()); + } else { + return object.getActualInstance(); + } + } + + /** + * Get the schema type (e.g. anyOf, oneOf) + * + * @return the schema type + */ + public String getSchemaType() { + return schemaType; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ").append(getClass()).append(" {\n"); + sb.append(" instance: ").append(toIndentedString(instance)).append("\n"); + sb.append(" isNullable: ").append(toIndentedString(isNullable)).append("\n"); + sb.append(" schemaType: ").append(toIndentedString(schemaType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AbstractOpenApiSchema a = (AbstractOpenApiSchema) o; + return Objects.equals(this.instance, a.instance) && + Objects.equals(this.isNullable, a.isNullable) && + Objects.equals(this.schemaType, a.schemaType); + } + + @Override + public int hashCode() { + return Objects.hash(instance, isNullable, schemaType); + } + + /** + * Is nullable + * + * @return true if it's nullable + */ + public Boolean isNullable() { + if (Boolean.TRUE.equals(isNullable)) { + return Boolean.TRUE; + } else { + return Boolean.FALSE; + } + } + + + +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java new file mode 100644 index 00000000..d74aea01 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/CancelStatus.java @@ -0,0 +1,332 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.UUID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * CancelStatus + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class CancelStatus { + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_SQL_STATE = "sqlState"; + @SerializedName(SERIALIZED_NAME_SQL_STATE) + @javax.annotation.Nullable + private String sqlState; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_STATEMENT_HANDLE = "statementHandle"; + @SerializedName(SERIALIZED_NAME_STATEMENT_HANDLE) + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String SERIALIZED_NAME_STATEMENT_STATUS_URL = "statementStatusUrl"; + @SerializedName(SERIALIZED_NAME_STATEMENT_STATUS_URL) + @javax.annotation.Nullable + private URI statementStatusUrl; + + public CancelStatus() { + } + + public CancelStatus code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public CancelStatus sqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + public String getSqlState() { + return sqlState; + } + + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + + public CancelStatus message(@javax.annotation.Nullable String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + + public CancelStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + public UUID getStatementHandle() { + return statementHandle; + } + + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + + public CancelStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CancelStatus cancelStatus = (CancelStatus) o; + return Objects.equals(this.code, cancelStatus.code) && + Objects.equals(this.sqlState, cancelStatus.sqlState) && + Objects.equals(this.message, cancelStatus.message) && + Objects.equals(this.statementHandle, cancelStatus.statementHandle) && + Objects.equals(this.statementStatusUrl, cancelStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class CancelStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("code", "sqlState", "message", "statementHandle", "statementStatusUrl")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("statementHandle")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to CancelStatus + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!CancelStatus.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in CancelStatus is not found in the empty JSON string", CancelStatus.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!CancelStatus.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `CancelStatus` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : CancelStatus.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("sqlState") != null && !jsonObj.get("sqlState").isJsonNull()) && !jsonObj.get("sqlState").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `sqlState` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sqlState").toString())); + } + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if (!jsonObj.get("statementHandle").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementHandle` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementHandle").toString())); + } + if ((jsonObj.get("statementStatusUrl") != null && !jsonObj.get("statementStatusUrl").isJsonNull()) && !jsonObj.get("statementStatusUrl").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementStatusUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementStatusUrl").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!CancelStatus.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'CancelStatus' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(CancelStatus.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, CancelStatus value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public CancelStatus read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of CancelStatus given an JSON string + * + * @param jsonString JSON string + * @return An instance of CancelStatus + * @throws IOException if the JSON string is invalid with respect to CancelStatus + */ + public static CancelStatus fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, CancelStatus.class); + } + + /** + * Convert an instance of CancelStatus to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java new file mode 100644 index 00000000..d2b7b26a --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ErrorResponse.java @@ -0,0 +1,295 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ErrorResponse + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ErrorResponse { + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_ERROR_CODE = "error_code"; + @SerializedName(SERIALIZED_NAME_ERROR_CODE) + @javax.annotation.Nullable + private String errorCode; + + public static final String SERIALIZED_NAME_REQUEST_ID = "request_id"; + @SerializedName(SERIALIZED_NAME_REQUEST_ID) + @javax.annotation.Nullable + private String requestId; + + public ErrorResponse() { + } + + public ErrorResponse message(@javax.annotation.Nullable String message) { + this.message = message; + return this; + } + + /** + * Error message returned by the server + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + + public ErrorResponse code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Error code. + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public ErrorResponse errorCode(@javax.annotation.Nullable String errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * Error code, same as `code` above. This property has been deprecated and will be removed in a future release, but is temporarily supported for for short-term backward compatibility. + * @return errorCode + */ + @javax.annotation.Nullable + public String getErrorCode() { + return errorCode; + } + + public void setErrorCode(@javax.annotation.Nullable String errorCode) { + this.errorCode = errorCode; + } + + + public ErrorResponse requestId(@javax.annotation.Nullable String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Unique request ID. + * @return requestId + */ + @javax.annotation.Nullable + public String getRequestId() { + return requestId; + } + + public void setRequestId(@javax.annotation.Nullable String requestId) { + this.requestId = requestId; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ErrorResponse errorResponse = (ErrorResponse) o; + return Objects.equals(this.message, errorResponse.message) && + Objects.equals(this.code, errorResponse.code) && + Objects.equals(this.errorCode, errorResponse.errorCode) && + Objects.equals(this.requestId, errorResponse.requestId); + } + + @Override + public int hashCode() { + return Objects.hash(message, code, errorCode, requestId); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ErrorResponse {\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" errorCode: ").append(toIndentedString(errorCode)).append("\n"); + sb.append(" requestId: ").append(toIndentedString(requestId)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("message", "code", "error_code", "request_id")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ErrorResponse + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ErrorResponse.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ErrorResponse is not found in the empty JSON string", ErrorResponse.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ErrorResponse.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ErrorResponse` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("error_code") != null && !jsonObj.get("error_code").isJsonNull()) && !jsonObj.get("error_code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `error_code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("error_code").toString())); + } + if ((jsonObj.get("request_id") != null && !jsonObj.get("request_id").isJsonNull()) && !jsonObj.get("request_id").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `request_id` to be a primitive type in the JSON string but got `%s`", jsonObj.get("request_id").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ErrorResponse.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ErrorResponse' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ErrorResponse.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ErrorResponse value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ErrorResponse read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ErrorResponse given an JSON string + * + * @param jsonString JSON string + * @return An instance of ErrorResponse + * @throws IOException if the JSON string is invalid with respect to ErrorResponse + */ + public static ErrorResponse fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ErrorResponse.class); + } + + /** + * Convert an instance of ErrorResponse to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java new file mode 100644 index 00000000..edfc5388 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/FetchServiceLogs200Response.java @@ -0,0 +1,207 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * FetchServiceLogs200Response + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class FetchServiceLogs200Response { + public static final String SERIALIZED_NAME_SYSTEM$GET_SERVICE_LOGS = "system$get_service_logs"; + @SerializedName(SERIALIZED_NAME_SYSTEM$GET_SERVICE_LOGS) + @javax.annotation.Nullable + private String system$getServiceLogs; + + public FetchServiceLogs200Response() { + } + + public FetchServiceLogs200Response system$getServiceLogs(@javax.annotation.Nullable String system$getServiceLogs) { + this.system$getServiceLogs = system$getServiceLogs; + return this; + } + + /** + * Get system$getServiceLogs + * @return system$getServiceLogs + */ + @javax.annotation.Nullable + public String getSystem$getServiceLogs() { + return system$getServiceLogs; + } + + public void setSystem$getServiceLogs(@javax.annotation.Nullable String system$getServiceLogs) { + this.system$getServiceLogs = system$getServiceLogs; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FetchServiceLogs200Response fetchServiceLogs200Response = (FetchServiceLogs200Response) o; + return Objects.equals(this.system$getServiceLogs, fetchServiceLogs200Response.system$getServiceLogs); + } + + @Override + public int hashCode() { + return Objects.hash(system$getServiceLogs); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class FetchServiceLogs200Response {\n"); + sb.append(" system$getServiceLogs: ").append(toIndentedString(system$getServiceLogs)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("system$get_service_logs")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to FetchServiceLogs200Response + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!FetchServiceLogs200Response.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in FetchServiceLogs200Response is not found in the empty JSON string", FetchServiceLogs200Response.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!FetchServiceLogs200Response.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `FetchServiceLogs200Response` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("system$get_service_logs") != null && !jsonObj.get("system$get_service_logs").isJsonNull()) && !jsonObj.get("system$get_service_logs").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `system$get_service_logs` to be a primitive type in the JSON string but got `%s`", jsonObj.get("system$get_service_logs").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!FetchServiceLogs200Response.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'FetchServiceLogs200Response' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(FetchServiceLogs200Response.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, FetchServiceLogs200Response value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public FetchServiceLogs200Response read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of FetchServiceLogs200Response given an JSON string + * + * @param jsonString JSON string + * @return An instance of FetchServiceLogs200Response + * @throws IOException if the JSON string is invalid with respect to FetchServiceLogs200Response + */ + public static FetchServiceLogs200Response fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, FetchServiceLogs200Response.class); + } + + /** + * Convert an instance of FetchServiceLogs200Response to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java new file mode 100644 index 00000000..f9939d3f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryFailureStatus.java @@ -0,0 +1,358 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.UUID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * QueryFailureStatus + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class QueryFailureStatus { + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_SQL_STATE = "sqlState"; + @SerializedName(SERIALIZED_NAME_SQL_STATE) + @javax.annotation.Nullable + private String sqlState; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nonnull + private String message; + + public static final String SERIALIZED_NAME_STATEMENT_HANDLE = "statementHandle"; + @SerializedName(SERIALIZED_NAME_STATEMENT_HANDLE) + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String SERIALIZED_NAME_CREATED_ON = "createdOn"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private Long createdOn; + + public static final String SERIALIZED_NAME_STATEMENT_STATUS_URL = "statementStatusUrl"; + @SerializedName(SERIALIZED_NAME_STATEMENT_STATUS_URL) + @javax.annotation.Nullable + private URI statementStatusUrl; + + public QueryFailureStatus() { + } + + public QueryFailureStatus code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public QueryFailureStatus sqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + public String getSqlState() { + return sqlState; + } + + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + + public QueryFailureStatus message(@javax.annotation.Nonnull String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nonnull + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nonnull String message) { + this.message = message; + } + + + public QueryFailureStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + public UUID getStatementHandle() { + return statementHandle; + } + + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + + public QueryFailureStatus createdOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started.‌ The timestamp is expressed in milliseconds since the epoch. + * @return createdOn + */ + @javax.annotation.Nullable + public Long getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + + public QueryFailureStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + QueryFailureStatus queryFailureStatus = (QueryFailureStatus) o; + return Objects.equals(this.code, queryFailureStatus.code) && + Objects.equals(this.sqlState, queryFailureStatus.sqlState) && + Objects.equals(this.message, queryFailureStatus.message) && + Objects.equals(this.statementHandle, queryFailureStatus.statementHandle) && + Objects.equals(this.createdOn, queryFailureStatus.createdOn) && + Objects.equals(this.statementStatusUrl, queryFailureStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class QueryFailureStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("code", "sqlState", "message", "statementHandle", "createdOn", "statementStatusUrl")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("message", "statementHandle")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to QueryFailureStatus + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!QueryFailureStatus.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in QueryFailureStatus is not found in the empty JSON string", QueryFailureStatus.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!QueryFailureStatus.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `QueryFailureStatus` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : QueryFailureStatus.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("sqlState") != null && !jsonObj.get("sqlState").isJsonNull()) && !jsonObj.get("sqlState").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `sqlState` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sqlState").toString())); + } + if (!jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if (!jsonObj.get("statementHandle").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementHandle` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementHandle").toString())); + } + if ((jsonObj.get("statementStatusUrl") != null && !jsonObj.get("statementStatusUrl").isJsonNull()) && !jsonObj.get("statementStatusUrl").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementStatusUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementStatusUrl").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!QueryFailureStatus.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'QueryFailureStatus' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(QueryFailureStatus.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, QueryFailureStatus value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public QueryFailureStatus read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of QueryFailureStatus given an JSON string + * + * @param jsonString JSON string + * @return An instance of QueryFailureStatus + * @throws IOException if the JSON string is invalid with respect to QueryFailureStatus + */ + public static QueryFailureStatus fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, QueryFailureStatus.class); + } + + /** + * Convert an instance of QueryFailureStatus to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java new file mode 100644 index 00000000..81fd5f02 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/QueryStatus.java @@ -0,0 +1,358 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.UUID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * QueryStatus + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class QueryStatus { + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_SQL_STATE = "sqlState"; + @SerializedName(SERIALIZED_NAME_SQL_STATE) + @javax.annotation.Nullable + private String sqlState; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_STATEMENT_HANDLE = "statementHandle"; + @SerializedName(SERIALIZED_NAME_STATEMENT_HANDLE) + @javax.annotation.Nonnull + private UUID statementHandle; + + public static final String SERIALIZED_NAME_CREATED_ON = "createdOn"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private Long createdOn; + + public static final String SERIALIZED_NAME_STATEMENT_STATUS_URL = "statementStatusUrl"; + @SerializedName(SERIALIZED_NAME_STATEMENT_STATUS_URL) + @javax.annotation.Nullable + private URI statementStatusUrl; + + public QueryStatus() { + } + + public QueryStatus code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public QueryStatus sqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + public String getSqlState() { + return sqlState; + } + + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + + public QueryStatus message(@javax.annotation.Nullable String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + + public QueryStatus statementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nonnull + public UUID getStatementHandle() { + return statementHandle; + } + + public void setStatementHandle(@javax.annotation.Nonnull UUID statementHandle) { + this.statementHandle = statementHandle; + } + + + public QueryStatus createdOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started. The timestamp is expressed in milliseconds since the epoch. + * @return createdOn + */ + @javax.annotation.Nullable + public Long getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + + public QueryStatus statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * URL that you can use to check the status of the execution of the statement and the result set. + * @return statementStatusUrl + */ + @javax.annotation.Nullable + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + QueryStatus queryStatus = (QueryStatus) o; + return Objects.equals(this.code, queryStatus.code) && + Objects.equals(this.sqlState, queryStatus.sqlState) && + Objects.equals(this.message, queryStatus.message) && + Objects.equals(this.statementHandle, queryStatus.statementHandle) && + Objects.equals(this.createdOn, queryStatus.createdOn) && + Objects.equals(this.statementStatusUrl, queryStatus.statementStatusUrl); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class QueryStatus {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("code", "sqlState", "message", "statementHandle", "createdOn", "statementStatusUrl")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("statementHandle")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to QueryStatus + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!QueryStatus.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in QueryStatus is not found in the empty JSON string", QueryStatus.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!QueryStatus.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `QueryStatus` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : QueryStatus.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("sqlState") != null && !jsonObj.get("sqlState").isJsonNull()) && !jsonObj.get("sqlState").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `sqlState` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sqlState").toString())); + } + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if (!jsonObj.get("statementHandle").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementHandle` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementHandle").toString())); + } + if ((jsonObj.get("statementStatusUrl") != null && !jsonObj.get("statementStatusUrl").isJsonNull()) && !jsonObj.get("statementStatusUrl").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementStatusUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementStatusUrl").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!QueryStatus.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'QueryStatus' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(QueryStatus.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, QueryStatus value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public QueryStatus read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of QueryStatus given an JSON string + * + * @param jsonString JSON string + * @return An instance of QueryStatus + * @throws IOException if the JSON string is invalid with respect to QueryStatus + */ + public static QueryStatus fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, QueryStatus.class); + } + + /** + * Convert an instance of QueryStatus to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java new file mode 100644 index 00000000..aadc8a98 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSet.java @@ -0,0 +1,453 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaData; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetStats; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ResultSet + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSet { + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_SQL_STATE = "sqlState"; + @SerializedName(SERIALIZED_NAME_SQL_STATE) + @javax.annotation.Nullable + private String sqlState; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_STATEMENT_HANDLE = "statementHandle"; + @SerializedName(SERIALIZED_NAME_STATEMENT_HANDLE) + @javax.annotation.Nullable + private UUID statementHandle; + + public static final String SERIALIZED_NAME_CREATED_ON = "createdOn"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private Long createdOn; + + public static final String SERIALIZED_NAME_STATEMENT_STATUS_URL = "statementStatusUrl"; + @SerializedName(SERIALIZED_NAME_STATEMENT_STATUS_URL) + @javax.annotation.Nullable + private URI statementStatusUrl; + + public static final String SERIALIZED_NAME_RESULT_SET_META_DATA = "resultSetMetaData"; + @SerializedName(SERIALIZED_NAME_RESULT_SET_META_DATA) + @javax.annotation.Nullable + private ResultSetResultSetMetaData resultSetMetaData; + + public static final String SERIALIZED_NAME_DATA = "data"; + @SerializedName(SERIALIZED_NAME_DATA) + @javax.annotation.Nullable + private List> data = new ArrayList<>(); + + public static final String SERIALIZED_NAME_STATS = "stats"; + @SerializedName(SERIALIZED_NAME_STATS) + @javax.annotation.Nullable + private ResultSetStats stats; + + public ResultSet() { + } + + public ResultSet code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Get code + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public ResultSet sqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + return this; + } + + /** + * Get sqlState + * @return sqlState + */ + @javax.annotation.Nullable + public String getSqlState() { + return sqlState; + } + + public void setSqlState(@javax.annotation.Nullable String sqlState) { + this.sqlState = sqlState; + } + + + public ResultSet message(@javax.annotation.Nullable String message) { + this.message = message; + return this; + } + + /** + * Get message + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + + public ResultSet statementHandle(@javax.annotation.Nullable UUID statementHandle) { + this.statementHandle = statementHandle; + return this; + } + + /** + * Get statementHandle + * @return statementHandle + */ + @javax.annotation.Nullable + public UUID getStatementHandle() { + return statementHandle; + } + + public void setStatementHandle(@javax.annotation.Nullable UUID statementHandle) { + this.statementHandle = statementHandle; + } + + + public ResultSet createdOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + return this; + } + + /** + * Timestamp that specifies when the statement execution started.‌ The timestamp is expressed in milliseconds since the epoch.‌ + * @return createdOn + */ + @javax.annotation.Nullable + public Long getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(@javax.annotation.Nullable Long createdOn) { + this.createdOn = createdOn; + } + + + public ResultSet statementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + return this; + } + + /** + * Get statementStatusUrl + * @return statementStatusUrl + */ + @javax.annotation.Nullable + public URI getStatementStatusUrl() { + return statementStatusUrl; + } + + public void setStatementStatusUrl(@javax.annotation.Nullable URI statementStatusUrl) { + this.statementStatusUrl = statementStatusUrl; + } + + + public ResultSet resultSetMetaData(@javax.annotation.Nullable ResultSetResultSetMetaData resultSetMetaData) { + this.resultSetMetaData = resultSetMetaData; + return this; + } + + /** + * Get resultSetMetaData + * @return resultSetMetaData + */ + @javax.annotation.Nullable + public ResultSetResultSetMetaData getResultSetMetaData() { + return resultSetMetaData; + } + + public void setResultSetMetaData(@javax.annotation.Nullable ResultSetResultSetMetaData resultSetMetaData) { + this.resultSetMetaData = resultSetMetaData; + } + + + public ResultSet data(@javax.annotation.Nullable List> data) { + this.data = data; + return this; + } + + public ResultSet addDataItem(List dataItem) { + if (this.data == null) { + this.data = new ArrayList<>(); + } + this.data.add(dataItem); + return this; + } + + /** + * Result set data. + * @return data + */ + @javax.annotation.Nullable + public List> getData() { + return data; + } + + public void setData(@javax.annotation.Nullable List> data) { + this.data = data; + } + + + public ResultSet stats(@javax.annotation.Nullable ResultSetStats stats) { + this.stats = stats; + return this; + } + + /** + * Get stats + * @return stats + */ + @javax.annotation.Nullable + public ResultSetStats getStats() { + return stats; + } + + public void setStats(@javax.annotation.Nullable ResultSetStats stats) { + this.stats = stats; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSet resultSet = (ResultSet) o; + return Objects.equals(this.code, resultSet.code) && + Objects.equals(this.sqlState, resultSet.sqlState) && + Objects.equals(this.message, resultSet.message) && + Objects.equals(this.statementHandle, resultSet.statementHandle) && + Objects.equals(this.createdOn, resultSet.createdOn) && + Objects.equals(this.statementStatusUrl, resultSet.statementStatusUrl) && + Objects.equals(this.resultSetMetaData, resultSet.resultSetMetaData) && + Objects.equals(this.data, resultSet.data) && + Objects.equals(this.stats, resultSet.stats); + } + + @Override + public int hashCode() { + return Objects.hash(code, sqlState, message, statementHandle, createdOn, statementStatusUrl, resultSetMetaData, data, stats); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSet {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" sqlState: ").append(toIndentedString(sqlState)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" statementHandle: ").append(toIndentedString(statementHandle)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" statementStatusUrl: ").append(toIndentedString(statementStatusUrl)).append("\n"); + sb.append(" resultSetMetaData: ").append(toIndentedString(resultSetMetaData)).append("\n"); + sb.append(" data: ").append(toIndentedString(data)).append("\n"); + sb.append(" stats: ").append(toIndentedString(stats)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("code", "sqlState", "message", "statementHandle", "createdOn", "statementStatusUrl", "resultSetMetaData", "data", "stats")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSet + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSet.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSet is not found in the empty JSON string", ResultSet.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSet.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSet` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("sqlState") != null && !jsonObj.get("sqlState").isJsonNull()) && !jsonObj.get("sqlState").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `sqlState` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sqlState").toString())); + } + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if ((jsonObj.get("statementHandle") != null && !jsonObj.get("statementHandle").isJsonNull()) && !jsonObj.get("statementHandle").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementHandle` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementHandle").toString())); + } + if ((jsonObj.get("statementStatusUrl") != null && !jsonObj.get("statementStatusUrl").isJsonNull()) && !jsonObj.get("statementStatusUrl").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statementStatusUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statementStatusUrl").toString())); + } + // validate the optional field `resultSetMetaData` + if (jsonObj.get("resultSetMetaData") != null && !jsonObj.get("resultSetMetaData").isJsonNull()) { + ResultSetResultSetMetaData.validateJsonElement(jsonObj.get("resultSetMetaData")); + } + // ensure the optional json data is an array if present + if (jsonObj.get("data") != null && !jsonObj.get("data").isJsonNull() && !jsonObj.get("data").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `data` to be an array in the JSON string but got `%s`", jsonObj.get("data").toString())); + } + // validate the optional field `stats` + if (jsonObj.get("stats") != null && !jsonObj.get("stats").isJsonNull()) { + ResultSetStats.validateJsonElement(jsonObj.get("stats")); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSet.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSet' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSet.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSet value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSet read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSet given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSet + * @throws IOException if the JSON string is invalid with respect to ResultSet + */ + public static ResultSet fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSet.class); + } + + /** + * Convert an instance of ResultSet to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java new file mode 100644 index 00000000..8defef35 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaData.java @@ -0,0 +1,444 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataParameters; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataPartitionInfoInner; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ResultSetResultSetMetaDataRowTypeInner; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ResultSetResultSetMetaData + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaData { + /** + * For v2 endpoints the only possible value for this field is jsonv2. + */ + @JsonAdapter(FormatEnum.Adapter.class) + public enum FormatEnum { + JSONV2("jsonv2"); + + private String value; + + FormatEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static FormatEnum fromValue(String value) { + for (FormatEnum b : FormatEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + + public static class Adapter extends TypeAdapter { + @Override + public void write(final JsonWriter jsonWriter, final FormatEnum enumeration) throws IOException { + jsonWriter.value(enumeration.getValue()); + } + + @Override + public FormatEnum read(final JsonReader jsonReader) throws IOException { + String value = jsonReader.nextString(); + return FormatEnum.fromValue(value); + } + } + + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + String value = jsonElement.getAsString(); + FormatEnum.fromValue(value); + } + } + + public static final String SERIALIZED_NAME_FORMAT = "format"; + @SerializedName(SERIALIZED_NAME_FORMAT) + @javax.annotation.Nullable + private FormatEnum format; + + public static final String SERIALIZED_NAME_NUM_ROWS = "numRows"; + @SerializedName(SERIALIZED_NAME_NUM_ROWS) + @javax.annotation.Nullable + private Long numRows; + + public static final String SERIALIZED_NAME_ROW_TYPE = "rowType"; + @SerializedName(SERIALIZED_NAME_ROW_TYPE) + @javax.annotation.Nullable + private List rowType = new ArrayList<>(); + + public static final String SERIALIZED_NAME_PARTITION_INFO = "partitionInfo"; + @SerializedName(SERIALIZED_NAME_PARTITION_INFO) + @javax.annotation.Nullable + private List partitionInfo = new ArrayList<>(); + + public static final String SERIALIZED_NAME_NULLABLE = "nullable"; + @SerializedName(SERIALIZED_NAME_NULLABLE) + @javax.annotation.Nullable + private Boolean nullable; + + public static final String SERIALIZED_NAME_PARAMETERS = "parameters"; + @SerializedName(SERIALIZED_NAME_PARAMETERS) + @javax.annotation.Nullable + private ResultSetResultSetMetaDataParameters parameters; + + public ResultSetResultSetMetaData() { + } + + public ResultSetResultSetMetaData format(@javax.annotation.Nullable FormatEnum format) { + this.format = format; + return this; + } + + /** + * For v2 endpoints the only possible value for this field is jsonv2. + * @return format + */ + @javax.annotation.Nullable + public FormatEnum getFormat() { + return format; + } + + public void setFormat(@javax.annotation.Nullable FormatEnum format) { + this.format = format; + } + + + public ResultSetResultSetMetaData numRows(@javax.annotation.Nullable Long numRows) { + this.numRows = numRows; + return this; + } + + /** + * The total number of rows of results. + * @return numRows + */ + @javax.annotation.Nullable + public Long getNumRows() { + return numRows; + } + + public void setNumRows(@javax.annotation.Nullable Long numRows) { + this.numRows = numRows; + } + + + public ResultSetResultSetMetaData rowType(@javax.annotation.Nullable List rowType) { + this.rowType = rowType; + return this; + } + + public ResultSetResultSetMetaData addRowTypeItem(ResultSetResultSetMetaDataRowTypeInner rowTypeItem) { + if (this.rowType == null) { + this.rowType = new ArrayList<>(); + } + this.rowType.add(rowTypeItem); + return this; + } + + /** + * Get rowType + * @return rowType + */ + @javax.annotation.Nullable + public List getRowType() { + return rowType; + } + + public void setRowType(@javax.annotation.Nullable List rowType) { + this.rowType = rowType; + } + + + public ResultSetResultSetMetaData partitionInfo(@javax.annotation.Nullable List partitionInfo) { + this.partitionInfo = partitionInfo; + return this; + } + + public ResultSetResultSetMetaData addPartitionInfoItem(ResultSetResultSetMetaDataPartitionInfoInner partitionInfoItem) { + if (this.partitionInfo == null) { + this.partitionInfo = new ArrayList<>(); + } + this.partitionInfo.add(partitionInfoItem); + return this; + } + + /** + * Partition information + * @return partitionInfo + */ + @javax.annotation.Nullable + public List getPartitionInfo() { + return partitionInfo; + } + + public void setPartitionInfo(@javax.annotation.Nullable List partitionInfo) { + this.partitionInfo = partitionInfo; + } + + + public ResultSetResultSetMetaData nullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + return this; + } + + /** + * false if null is replaced with a string 'null' otherwise false + * @return nullable + */ + @javax.annotation.Nullable + public Boolean getNullable() { + return nullable; + } + + public void setNullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + } + + + public ResultSetResultSetMetaData parameters(@javax.annotation.Nullable ResultSetResultSetMetaDataParameters parameters) { + this.parameters = parameters; + return this; + } + + /** + * Get parameters + * @return parameters + */ + @javax.annotation.Nullable + public ResultSetResultSetMetaDataParameters getParameters() { + return parameters; + } + + public void setParameters(@javax.annotation.Nullable ResultSetResultSetMetaDataParameters parameters) { + this.parameters = parameters; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaData resultSetResultSetMetaData = (ResultSetResultSetMetaData) o; + return Objects.equals(this.format, resultSetResultSetMetaData.format) && + Objects.equals(this.numRows, resultSetResultSetMetaData.numRows) && + Objects.equals(this.rowType, resultSetResultSetMetaData.rowType) && + Objects.equals(this.partitionInfo, resultSetResultSetMetaData.partitionInfo) && + Objects.equals(this.nullable, resultSetResultSetMetaData.nullable) && + Objects.equals(this.parameters, resultSetResultSetMetaData.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(format, numRows, rowType, partitionInfo, nullable, parameters); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaData {\n"); + sb.append(" format: ").append(toIndentedString(format)).append("\n"); + sb.append(" numRows: ").append(toIndentedString(numRows)).append("\n"); + sb.append(" rowType: ").append(toIndentedString(rowType)).append("\n"); + sb.append(" partitionInfo: ").append(toIndentedString(partitionInfo)).append("\n"); + sb.append(" nullable: ").append(toIndentedString(nullable)).append("\n"); + sb.append(" parameters: ").append(toIndentedString(parameters)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("format", "numRows", "rowType", "partitionInfo", "nullable", "parameters")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSetResultSetMetaData + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSetResultSetMetaData.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSetResultSetMetaData is not found in the empty JSON string", ResultSetResultSetMetaData.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSetResultSetMetaData.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSetResultSetMetaData` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("format") != null && !jsonObj.get("format").isJsonNull()) && !jsonObj.get("format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("format").toString())); + } + // validate the optional field `format` + if (jsonObj.get("format") != null && !jsonObj.get("format").isJsonNull()) { + FormatEnum.validateJsonElement(jsonObj.get("format")); + } + if (jsonObj.get("rowType") != null && !jsonObj.get("rowType").isJsonNull()) { + JsonArray jsonArrayrowType = jsonObj.getAsJsonArray("rowType"); + if (jsonArrayrowType != null) { + // ensure the json data is an array + if (!jsonObj.get("rowType").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `rowType` to be an array in the JSON string but got `%s`", jsonObj.get("rowType").toString())); + } + + // validate the optional field `rowType` (array) + for (int i = 0; i < jsonArrayrowType.size(); i++) { + ResultSetResultSetMetaDataRowTypeInner.validateJsonElement(jsonArrayrowType.get(i)); + }; + } + } + if (jsonObj.get("partitionInfo") != null && !jsonObj.get("partitionInfo").isJsonNull()) { + JsonArray jsonArraypartitionInfo = jsonObj.getAsJsonArray("partitionInfo"); + if (jsonArraypartitionInfo != null) { + // ensure the json data is an array + if (!jsonObj.get("partitionInfo").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `partitionInfo` to be an array in the JSON string but got `%s`", jsonObj.get("partitionInfo").toString())); + } + + // validate the optional field `partitionInfo` (array) + for (int i = 0; i < jsonArraypartitionInfo.size(); i++) { + ResultSetResultSetMetaDataPartitionInfoInner.validateJsonElement(jsonArraypartitionInfo.get(i)); + }; + } + } + // validate the optional field `parameters` + if (jsonObj.get("parameters") != null && !jsonObj.get("parameters").isJsonNull()) { + ResultSetResultSetMetaDataParameters.validateJsonElement(jsonObj.get("parameters")); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSetResultSetMetaData.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSetResultSetMetaData' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSetResultSetMetaData.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSetResultSetMetaData value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSetResultSetMetaData read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSetResultSetMetaData given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSetResultSetMetaData + * @throws IOException if the JSON string is invalid with respect to ResultSetResultSetMetaData + */ + public static ResultSetResultSetMetaData fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSetResultSetMetaData.class); + } + + /** + * Convert an instance of ResultSetResultSetMetaData to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java new file mode 100644 index 00000000..4b03fe10 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataParameters.java @@ -0,0 +1,407 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ResultSetResultSetMetaDataParameters + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataParameters { + public static final String SERIALIZED_NAME_BINARY_OUTPUT_FORMAT = "binary_output_format"; + @SerializedName(SERIALIZED_NAME_BINARY_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String binaryOutputFormat; + + public static final String SERIALIZED_NAME_DATE_OUTPUT_FORMAT = "date_output_format"; + @SerializedName(SERIALIZED_NAME_DATE_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String dateOutputFormat; + + public static final String SERIALIZED_NAME_TIME_OUTPUT_FORMAT = "time_output_format"; + @SerializedName(SERIALIZED_NAME_TIME_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timeOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_OUTPUT_FORMAT = "timestamp_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_LTZ_OUTPUT_FORMAT = "timestamp_ltz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_LTZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampLtzOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_NTZ_OUTPUT_FORMAT = "timestamp_ntz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_NTZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampNtzOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_TZ_OUTPUT_FORMAT = "timestamp_tz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_TZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampTzOutputFormat; + + public static final String SERIALIZED_NAME_MULTI_STATEMENT_COUNT = "multi_statement_count"; + @SerializedName(SERIALIZED_NAME_MULTI_STATEMENT_COUNT) + @javax.annotation.Nullable + private Integer multiStatementCount; + + public ResultSetResultSetMetaDataParameters() { + } + + public ResultSetResultSetMetaDataParameters binaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + return this; + } + + /** + * Get binaryOutputFormat + * @return binaryOutputFormat + */ + @javax.annotation.Nullable + public String getBinaryOutputFormat() { + return binaryOutputFormat; + } + + public void setBinaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters dateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + return this; + } + + /** + * Get dateOutputFormat + * @return dateOutputFormat + */ + @javax.annotation.Nullable + public String getDateOutputFormat() { + return dateOutputFormat; + } + + public void setDateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters timeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + return this; + } + + /** + * Get timeOutputFormat + * @return timeOutputFormat + */ + @javax.annotation.Nullable + public String getTimeOutputFormat() { + return timeOutputFormat; + } + + public void setTimeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters timestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + return this; + } + + /** + * Get timestampOutputFormat + * @return timestampOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampOutputFormat() { + return timestampOutputFormat; + } + + public void setTimestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters timestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + return this; + } + + /** + * Get timestampLtzOutputFormat + * @return timestampLtzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampLtzOutputFormat() { + return timestampLtzOutputFormat; + } + + public void setTimestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters timestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + return this; + } + + /** + * Get timestampNtzOutputFormat + * @return timestampNtzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampNtzOutputFormat() { + return timestampNtzOutputFormat; + } + + public void setTimestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters timestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + return this; + } + + /** + * Get timestampTzOutputFormat + * @return timestampTzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampTzOutputFormat() { + return timestampTzOutputFormat; + } + + public void setTimestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + } + + + public ResultSetResultSetMetaDataParameters multiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + return this; + } + + /** + * Get multiStatementCount + * @return multiStatementCount + */ + @javax.annotation.Nullable + public Integer getMultiStatementCount() { + return multiStatementCount; + } + + public void setMultiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataParameters resultSetResultSetMetaDataParameters = (ResultSetResultSetMetaDataParameters) o; + return Objects.equals(this.binaryOutputFormat, resultSetResultSetMetaDataParameters.binaryOutputFormat) && + Objects.equals(this.dateOutputFormat, resultSetResultSetMetaDataParameters.dateOutputFormat) && + Objects.equals(this.timeOutputFormat, resultSetResultSetMetaDataParameters.timeOutputFormat) && + Objects.equals(this.timestampOutputFormat, resultSetResultSetMetaDataParameters.timestampOutputFormat) && + Objects.equals(this.timestampLtzOutputFormat, resultSetResultSetMetaDataParameters.timestampLtzOutputFormat) && + Objects.equals(this.timestampNtzOutputFormat, resultSetResultSetMetaDataParameters.timestampNtzOutputFormat) && + Objects.equals(this.timestampTzOutputFormat, resultSetResultSetMetaDataParameters.timestampTzOutputFormat) && + Objects.equals(this.multiStatementCount, resultSetResultSetMetaDataParameters.multiStatementCount); + } + + @Override + public int hashCode() { + return Objects.hash(binaryOutputFormat, dateOutputFormat, timeOutputFormat, timestampOutputFormat, timestampLtzOutputFormat, timestampNtzOutputFormat, timestampTzOutputFormat, multiStatementCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataParameters {\n"); + sb.append(" binaryOutputFormat: ").append(toIndentedString(binaryOutputFormat)).append("\n"); + sb.append(" dateOutputFormat: ").append(toIndentedString(dateOutputFormat)).append("\n"); + sb.append(" timeOutputFormat: ").append(toIndentedString(timeOutputFormat)).append("\n"); + sb.append(" timestampOutputFormat: ").append(toIndentedString(timestampOutputFormat)).append("\n"); + sb.append(" timestampLtzOutputFormat: ").append(toIndentedString(timestampLtzOutputFormat)).append("\n"); + sb.append(" timestampNtzOutputFormat: ").append(toIndentedString(timestampNtzOutputFormat)).append("\n"); + sb.append(" timestampTzOutputFormat: ").append(toIndentedString(timestampTzOutputFormat)).append("\n"); + sb.append(" multiStatementCount: ").append(toIndentedString(multiStatementCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("binary_output_format", "date_output_format", "time_output_format", "timestamp_output_format", "timestamp_ltz_output_format", "timestamp_ntz_output_format", "timestamp_tz_output_format", "multi_statement_count")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSetResultSetMetaDataParameters + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSetResultSetMetaDataParameters.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSetResultSetMetaDataParameters is not found in the empty JSON string", ResultSetResultSetMetaDataParameters.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSetResultSetMetaDataParameters.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSetResultSetMetaDataParameters` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("binary_output_format") != null && !jsonObj.get("binary_output_format").isJsonNull()) && !jsonObj.get("binary_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `binary_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("binary_output_format").toString())); + } + if ((jsonObj.get("date_output_format") != null && !jsonObj.get("date_output_format").isJsonNull()) && !jsonObj.get("date_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `date_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("date_output_format").toString())); + } + if ((jsonObj.get("time_output_format") != null && !jsonObj.get("time_output_format").isJsonNull()) && !jsonObj.get("time_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `time_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("time_output_format").toString())); + } + if ((jsonObj.get("timestamp_output_format") != null && !jsonObj.get("timestamp_output_format").isJsonNull()) && !jsonObj.get("timestamp_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_output_format").toString())); + } + if ((jsonObj.get("timestamp_ltz_output_format") != null && !jsonObj.get("timestamp_ltz_output_format").isJsonNull()) && !jsonObj.get("timestamp_ltz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_ltz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_ltz_output_format").toString())); + } + if ((jsonObj.get("timestamp_ntz_output_format") != null && !jsonObj.get("timestamp_ntz_output_format").isJsonNull()) && !jsonObj.get("timestamp_ntz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_ntz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_ntz_output_format").toString())); + } + if ((jsonObj.get("timestamp_tz_output_format") != null && !jsonObj.get("timestamp_tz_output_format").isJsonNull()) && !jsonObj.get("timestamp_tz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_tz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_tz_output_format").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSetResultSetMetaDataParameters.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSetResultSetMetaDataParameters' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSetResultSetMetaDataParameters.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSetResultSetMetaDataParameters value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSetResultSetMetaDataParameters read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSetResultSetMetaDataParameters given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSetResultSetMetaDataParameters + * @throws IOException if the JSON string is invalid with respect to ResultSetResultSetMetaDataParameters + */ + public static ResultSetResultSetMetaDataParameters fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSetResultSetMetaDataParameters.class); + } + + /** + * Convert an instance of ResultSetResultSetMetaDataParameters to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java new file mode 100644 index 00000000..3813c57c --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataPartitionInfoInner.java @@ -0,0 +1,259 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ResultSetResultSetMetaDataPartitionInfoInner + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataPartitionInfoInner { + public static final String SERIALIZED_NAME_ROW_COUNT = "rowCount"; + @SerializedName(SERIALIZED_NAME_ROW_COUNT) + @javax.annotation.Nullable + private Long rowCount; + + public static final String SERIALIZED_NAME_COMPRESSED_SIZE = "compressedSize"; + @SerializedName(SERIALIZED_NAME_COMPRESSED_SIZE) + @javax.annotation.Nullable + private Long compressedSize; + + public static final String SERIALIZED_NAME_UNCOMPRESSED_SIZE = "uncompressedSize"; + @SerializedName(SERIALIZED_NAME_UNCOMPRESSED_SIZE) + @javax.annotation.Nullable + private Long uncompressedSize; + + public ResultSetResultSetMetaDataPartitionInfoInner() { + } + + public ResultSetResultSetMetaDataPartitionInfoInner rowCount(@javax.annotation.Nullable Long rowCount) { + this.rowCount = rowCount; + return this; + } + + /** + * Number of rows in the partition. + * minimum: 0 + * @return rowCount + */ + @javax.annotation.Nullable + public Long getRowCount() { + return rowCount; + } + + public void setRowCount(@javax.annotation.Nullable Long rowCount) { + this.rowCount = rowCount; + } + + + public ResultSetResultSetMetaDataPartitionInfoInner compressedSize(@javax.annotation.Nullable Long compressedSize) { + this.compressedSize = compressedSize; + return this; + } + + /** + * the partition size before the decompression. This may or may not be present in the partitionInfo. Uncompressed size would always be there. + * minimum: 0 + * @return compressedSize + */ + @javax.annotation.Nullable + public Long getCompressedSize() { + return compressedSize; + } + + public void setCompressedSize(@javax.annotation.Nullable Long compressedSize) { + this.compressedSize = compressedSize; + } + + + public ResultSetResultSetMetaDataPartitionInfoInner uncompressedSize(@javax.annotation.Nullable Long uncompressedSize) { + this.uncompressedSize = uncompressedSize; + return this; + } + + /** + * the partition size after the decompression + * minimum: 0 + * @return uncompressedSize + */ + @javax.annotation.Nullable + public Long getUncompressedSize() { + return uncompressedSize; + } + + public void setUncompressedSize(@javax.annotation.Nullable Long uncompressedSize) { + this.uncompressedSize = uncompressedSize; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataPartitionInfoInner resultSetResultSetMetaDataPartitionInfoInner = (ResultSetResultSetMetaDataPartitionInfoInner) o; + return Objects.equals(this.rowCount, resultSetResultSetMetaDataPartitionInfoInner.rowCount) && + Objects.equals(this.compressedSize, resultSetResultSetMetaDataPartitionInfoInner.compressedSize) && + Objects.equals(this.uncompressedSize, resultSetResultSetMetaDataPartitionInfoInner.uncompressedSize); + } + + @Override + public int hashCode() { + return Objects.hash(rowCount, compressedSize, uncompressedSize); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataPartitionInfoInner {\n"); + sb.append(" rowCount: ").append(toIndentedString(rowCount)).append("\n"); + sb.append(" compressedSize: ").append(toIndentedString(compressedSize)).append("\n"); + sb.append(" uncompressedSize: ").append(toIndentedString(uncompressedSize)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("rowCount", "compressedSize", "uncompressedSize")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSetResultSetMetaDataPartitionInfoInner + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSetResultSetMetaDataPartitionInfoInner.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSetResultSetMetaDataPartitionInfoInner is not found in the empty JSON string", ResultSetResultSetMetaDataPartitionInfoInner.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSetResultSetMetaDataPartitionInfoInner.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSetResultSetMetaDataPartitionInfoInner` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSetResultSetMetaDataPartitionInfoInner.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSetResultSetMetaDataPartitionInfoInner' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSetResultSetMetaDataPartitionInfoInner.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSetResultSetMetaDataPartitionInfoInner value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSetResultSetMetaDataPartitionInfoInner read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSetResultSetMetaDataPartitionInfoInner given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSetResultSetMetaDataPartitionInfoInner + * @throws IOException if the JSON string is invalid with respect to ResultSetResultSetMetaDataPartitionInfoInner + */ + public static ResultSetResultSetMetaDataPartitionInfoInner fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSetResultSetMetaDataPartitionInfoInner.class); + } + + /** + * Convert an instance of ResultSetResultSetMetaDataPartitionInfoInner to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java new file mode 100644 index 00000000..51402e39 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetResultSetMetaDataRowTypeInner.java @@ -0,0 +1,343 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ResultSetResultSetMetaDataRowTypeInner + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetResultSetMetaDataRowTypeInner { + public static final String SERIALIZED_NAME_NAME = "name"; + @SerializedName(SERIALIZED_NAME_NAME) + @javax.annotation.Nullable + private String name; + + public static final String SERIALIZED_NAME_TYPE = "type"; + @SerializedName(SERIALIZED_NAME_TYPE) + @javax.annotation.Nullable + private String type; + + public static final String SERIALIZED_NAME_LENGTH = "length"; + @SerializedName(SERIALIZED_NAME_LENGTH) + @javax.annotation.Nullable + private Long length; + + public static final String SERIALIZED_NAME_PRECISION = "precision"; + @SerializedName(SERIALIZED_NAME_PRECISION) + @javax.annotation.Nullable + private Long precision; + + public static final String SERIALIZED_NAME_SCALE = "scale"; + @SerializedName(SERIALIZED_NAME_SCALE) + @javax.annotation.Nullable + private Long scale; + + public static final String SERIALIZED_NAME_NULLABLE = "nullable"; + @SerializedName(SERIALIZED_NAME_NULLABLE) + @javax.annotation.Nullable + private Boolean nullable; + + public ResultSetResultSetMetaDataRowTypeInner() { + } + + public ResultSetResultSetMetaDataRowTypeInner name(@javax.annotation.Nullable String name) { + this.name = name; + return this; + } + + /** + * Get name + * @return name + */ + @javax.annotation.Nullable + public String getName() { + return name; + } + + public void setName(@javax.annotation.Nullable String name) { + this.name = name; + } + + + public ResultSetResultSetMetaDataRowTypeInner type(@javax.annotation.Nullable String type) { + this.type = type; + return this; + } + + /** + * Get type + * @return type + */ + @javax.annotation.Nullable + public String getType() { + return type; + } + + public void setType(@javax.annotation.Nullable String type) { + this.type = type; + } + + + public ResultSetResultSetMetaDataRowTypeInner length(@javax.annotation.Nullable Long length) { + this.length = length; + return this; + } + + /** + * Get length + * minimum: 0 + * @return length + */ + @javax.annotation.Nullable + public Long getLength() { + return length; + } + + public void setLength(@javax.annotation.Nullable Long length) { + this.length = length; + } + + + public ResultSetResultSetMetaDataRowTypeInner precision(@javax.annotation.Nullable Long precision) { + this.precision = precision; + return this; + } + + /** + * Get precision + * minimum: 0 + * @return precision + */ + @javax.annotation.Nullable + public Long getPrecision() { + return precision; + } + + public void setPrecision(@javax.annotation.Nullable Long precision) { + this.precision = precision; + } + + + public ResultSetResultSetMetaDataRowTypeInner scale(@javax.annotation.Nullable Long scale) { + this.scale = scale; + return this; + } + + /** + * Get scale + * minimum: 0 + * @return scale + */ + @javax.annotation.Nullable + public Long getScale() { + return scale; + } + + public void setScale(@javax.annotation.Nullable Long scale) { + this.scale = scale; + } + + + public ResultSetResultSetMetaDataRowTypeInner nullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + return this; + } + + /** + * Get nullable + * @return nullable + */ + @javax.annotation.Nullable + public Boolean getNullable() { + return nullable; + } + + public void setNullable(@javax.annotation.Nullable Boolean nullable) { + this.nullable = nullable; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetResultSetMetaDataRowTypeInner resultSetResultSetMetaDataRowTypeInner = (ResultSetResultSetMetaDataRowTypeInner) o; + return Objects.equals(this.name, resultSetResultSetMetaDataRowTypeInner.name) && + Objects.equals(this.type, resultSetResultSetMetaDataRowTypeInner.type) && + Objects.equals(this.length, resultSetResultSetMetaDataRowTypeInner.length) && + Objects.equals(this.precision, resultSetResultSetMetaDataRowTypeInner.precision) && + Objects.equals(this.scale, resultSetResultSetMetaDataRowTypeInner.scale) && + Objects.equals(this.nullable, resultSetResultSetMetaDataRowTypeInner.nullable); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, length, precision, scale, nullable); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetResultSetMetaDataRowTypeInner {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" length: ").append(toIndentedString(length)).append("\n"); + sb.append(" precision: ").append(toIndentedString(precision)).append("\n"); + sb.append(" scale: ").append(toIndentedString(scale)).append("\n"); + sb.append(" nullable: ").append(toIndentedString(nullable)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("name", "type", "length", "precision", "scale", "nullable")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSetResultSetMetaDataRowTypeInner + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSetResultSetMetaDataRowTypeInner.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSetResultSetMetaDataRowTypeInner is not found in the empty JSON string", ResultSetResultSetMetaDataRowTypeInner.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSetResultSetMetaDataRowTypeInner.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSetResultSetMetaDataRowTypeInner` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("name") != null && !jsonObj.get("name").isJsonNull()) && !jsonObj.get("name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("name").toString())); + } + if ((jsonObj.get("type") != null && !jsonObj.get("type").isJsonNull()) && !jsonObj.get("type").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `type` to be a primitive type in the JSON string but got `%s`", jsonObj.get("type").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSetResultSetMetaDataRowTypeInner.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSetResultSetMetaDataRowTypeInner' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSetResultSetMetaDataRowTypeInner.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSetResultSetMetaDataRowTypeInner value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSetResultSetMetaDataRowTypeInner read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSetResultSetMetaDataRowTypeInner given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSetResultSetMetaDataRowTypeInner + * @throws IOException if the JSON string is invalid with respect to ResultSetResultSetMetaDataRowTypeInner + */ + public static ResultSetResultSetMetaDataRowTypeInner fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSetResultSetMetaDataRowTypeInner.class); + } + + /** + * Convert an instance of ResultSetResultSetMetaDataRowTypeInner to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java new file mode 100644 index 00000000..cb9367d5 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ResultSetStats.java @@ -0,0 +1,286 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * these stats might not be available for each request. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ResultSetStats { + public static final String SERIALIZED_NAME_NUM_ROWS_INSERTED = "numRowsInserted"; + @SerializedName(SERIALIZED_NAME_NUM_ROWS_INSERTED) + @javax.annotation.Nullable + private Long numRowsInserted; + + public static final String SERIALIZED_NAME_NUM_ROWS_UPDATED = "numRowsUpdated"; + @SerializedName(SERIALIZED_NAME_NUM_ROWS_UPDATED) + @javax.annotation.Nullable + private Long numRowsUpdated; + + public static final String SERIALIZED_NAME_NUM_ROWS_DELETED = "numRowsDeleted"; + @SerializedName(SERIALIZED_NAME_NUM_ROWS_DELETED) + @javax.annotation.Nullable + private Long numRowsDeleted; + + public static final String SERIALIZED_NAME_NUM_DUPLICATE_ROWS_UPDATED = "numDuplicateRowsUpdated"; + @SerializedName(SERIALIZED_NAME_NUM_DUPLICATE_ROWS_UPDATED) + @javax.annotation.Nullable + private Long numDuplicateRowsUpdated; + + public ResultSetStats() { + } + + public ResultSetStats numRowsInserted(@javax.annotation.Nullable Long numRowsInserted) { + this.numRowsInserted = numRowsInserted; + return this; + } + + /** + * Number of rows that were inserted. + * minimum: 0 + * @return numRowsInserted + */ + @javax.annotation.Nullable + public Long getNumRowsInserted() { + return numRowsInserted; + } + + public void setNumRowsInserted(@javax.annotation.Nullable Long numRowsInserted) { + this.numRowsInserted = numRowsInserted; + } + + + public ResultSetStats numRowsUpdated(@javax.annotation.Nullable Long numRowsUpdated) { + this.numRowsUpdated = numRowsUpdated; + return this; + } + + /** + * Number of rows that were updated. + * minimum: 0 + * @return numRowsUpdated + */ + @javax.annotation.Nullable + public Long getNumRowsUpdated() { + return numRowsUpdated; + } + + public void setNumRowsUpdated(@javax.annotation.Nullable Long numRowsUpdated) { + this.numRowsUpdated = numRowsUpdated; + } + + + public ResultSetStats numRowsDeleted(@javax.annotation.Nullable Long numRowsDeleted) { + this.numRowsDeleted = numRowsDeleted; + return this; + } + + /** + * Number of rows that were deleted. + * minimum: 0 + * @return numRowsDeleted + */ + @javax.annotation.Nullable + public Long getNumRowsDeleted() { + return numRowsDeleted; + } + + public void setNumRowsDeleted(@javax.annotation.Nullable Long numRowsDeleted) { + this.numRowsDeleted = numRowsDeleted; + } + + + public ResultSetStats numDuplicateRowsUpdated(@javax.annotation.Nullable Long numDuplicateRowsUpdated) { + this.numDuplicateRowsUpdated = numDuplicateRowsUpdated; + return this; + } + + /** + * Number of duplicate rows that were updated. + * minimum: 0 + * @return numDuplicateRowsUpdated + */ + @javax.annotation.Nullable + public Long getNumDuplicateRowsUpdated() { + return numDuplicateRowsUpdated; + } + + public void setNumDuplicateRowsUpdated(@javax.annotation.Nullable Long numDuplicateRowsUpdated) { + this.numDuplicateRowsUpdated = numDuplicateRowsUpdated; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ResultSetStats resultSetStats = (ResultSetStats) o; + return Objects.equals(this.numRowsInserted, resultSetStats.numRowsInserted) && + Objects.equals(this.numRowsUpdated, resultSetStats.numRowsUpdated) && + Objects.equals(this.numRowsDeleted, resultSetStats.numRowsDeleted) && + Objects.equals(this.numDuplicateRowsUpdated, resultSetStats.numDuplicateRowsUpdated); + } + + @Override + public int hashCode() { + return Objects.hash(numRowsInserted, numRowsUpdated, numRowsDeleted, numDuplicateRowsUpdated); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResultSetStats {\n"); + sb.append(" numRowsInserted: ").append(toIndentedString(numRowsInserted)).append("\n"); + sb.append(" numRowsUpdated: ").append(toIndentedString(numRowsUpdated)).append("\n"); + sb.append(" numRowsDeleted: ").append(toIndentedString(numRowsDeleted)).append("\n"); + sb.append(" numDuplicateRowsUpdated: ").append(toIndentedString(numDuplicateRowsUpdated)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("numRowsInserted", "numRowsUpdated", "numRowsDeleted", "numDuplicateRowsUpdated")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ResultSetStats + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ResultSetStats.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ResultSetStats is not found in the empty JSON string", ResultSetStats.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ResultSetStats.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ResultSetStats` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ResultSetStats.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ResultSetStats' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ResultSetStats.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ResultSetStats value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ResultSetStats read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ResultSetStats given an JSON string + * + * @param jsonString JSON string + * @return An instance of ResultSetStats + * @throws IOException if the JSON string is invalid with respect to ResultSetStats + */ + public static ResultSetStats fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ResultSetStats.class); + } + + /** + * Convert an instance of ResultSetStats to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java new file mode 100644 index 00000000..6f0f0c40 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/Service.java @@ -0,0 +1,918 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * Service + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class Service { + public static final String SERIALIZED_NAME_NAME = "name"; + @SerializedName(SERIALIZED_NAME_NAME) + @javax.annotation.Nonnull + private String name; + + public static final String SERIALIZED_NAME_STATUS = "status"; + @SerializedName(SERIALIZED_NAME_STATUS) + @javax.annotation.Nullable + private String status; + + public static final String SERIALIZED_NAME_COMPUTE_POOL = "compute_pool"; + @SerializedName(SERIALIZED_NAME_COMPUTE_POOL) + @javax.annotation.Nonnull + private String computePool; + + public static final String SERIALIZED_NAME_SPEC = "spec"; + @SerializedName(SERIALIZED_NAME_SPEC) + @javax.annotation.Nonnull + private ServiceSpec spec; + + public static final String SERIALIZED_NAME_EXTERNAL_ACCESS_INTEGRATIONS = "external_access_integrations"; + @SerializedName(SERIALIZED_NAME_EXTERNAL_ACCESS_INTEGRATIONS) + @javax.annotation.Nullable + private List externalAccessIntegrations = new ArrayList<>(); + + public static final String SERIALIZED_NAME_QUERY_WAREHOUSE = "query_warehouse"; + @SerializedName(SERIALIZED_NAME_QUERY_WAREHOUSE) + @javax.annotation.Nullable + private String queryWarehouse; + + public static final String SERIALIZED_NAME_COMMENT = "comment"; + @SerializedName(SERIALIZED_NAME_COMMENT) + @javax.annotation.Nullable + private String comment; + + public static final String SERIALIZED_NAME_IS_ASYNC_JOB = "is_async_job"; + @SerializedName(SERIALIZED_NAME_IS_ASYNC_JOB) + @javax.annotation.Nullable + private Boolean isAsyncJob; + + public static final String SERIALIZED_NAME_AUTO_RESUME = "auto_resume"; + @SerializedName(SERIALIZED_NAME_AUTO_RESUME) + @javax.annotation.Nullable + private Boolean autoResume; + + public static final String SERIALIZED_NAME_CURRENT_INSTANCES = "current_instances"; + @SerializedName(SERIALIZED_NAME_CURRENT_INSTANCES) + @javax.annotation.Nullable + private Integer currentInstances; + + public static final String SERIALIZED_NAME_TARGET_INSTANCES = "target_instances"; + @SerializedName(SERIALIZED_NAME_TARGET_INSTANCES) + @javax.annotation.Nullable + private Integer targetInstances; + + public static final String SERIALIZED_NAME_MIN_READY_INSTANCES = "min_ready_instances"; + @SerializedName(SERIALIZED_NAME_MIN_READY_INSTANCES) + @javax.annotation.Nullable + private Integer minReadyInstances; + + public static final String SERIALIZED_NAME_MIN_INSTANCES = "min_instances"; + @SerializedName(SERIALIZED_NAME_MIN_INSTANCES) + @javax.annotation.Nullable + private Integer minInstances; + + public static final String SERIALIZED_NAME_MAX_INSTANCES = "max_instances"; + @SerializedName(SERIALIZED_NAME_MAX_INSTANCES) + @javax.annotation.Nullable + private Integer maxInstances; + + public static final String SERIALIZED_NAME_DATABASE_NAME = "database_name"; + @SerializedName(SERIALIZED_NAME_DATABASE_NAME) + @javax.annotation.Nullable + private String databaseName; + + public static final String SERIALIZED_NAME_SCHEMA_NAME = "schema_name"; + @SerializedName(SERIALIZED_NAME_SCHEMA_NAME) + @javax.annotation.Nullable + private String schemaName; + + public static final String SERIALIZED_NAME_OWNER = "owner"; + @SerializedName(SERIALIZED_NAME_OWNER) + @javax.annotation.Nullable + private String owner; + + public static final String SERIALIZED_NAME_DNS_NAME = "dns_name"; + @SerializedName(SERIALIZED_NAME_DNS_NAME) + @javax.annotation.Nullable + private String dnsName; + + public static final String SERIALIZED_NAME_CREATED_ON = "created_on"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String SERIALIZED_NAME_UPDATED_ON = "updated_on"; + @SerializedName(SERIALIZED_NAME_UPDATED_ON) + @javax.annotation.Nullable + private OffsetDateTime updatedOn; + + public static final String SERIALIZED_NAME_RESUMED_ON = "resumed_on"; + @SerializedName(SERIALIZED_NAME_RESUMED_ON) + @javax.annotation.Nullable + private OffsetDateTime resumedOn; + + public static final String SERIALIZED_NAME_SUSPENDED_ON = "suspended_on"; + @SerializedName(SERIALIZED_NAME_SUSPENDED_ON) + @javax.annotation.Nullable + private OffsetDateTime suspendedOn; + + public static final String SERIALIZED_NAME_AUTO_SUSPEND_SECS = "auto_suspend_secs"; + @SerializedName(SERIALIZED_NAME_AUTO_SUSPEND_SECS) + @javax.annotation.Nullable + private Long autoSuspendSecs; + + public static final String SERIALIZED_NAME_OWNER_ROLE_TYPE = "owner_role_type"; + @SerializedName(SERIALIZED_NAME_OWNER_ROLE_TYPE) + @javax.annotation.Nullable + private String ownerRoleType; + + public static final String SERIALIZED_NAME_IS_JOB = "is_job"; + @SerializedName(SERIALIZED_NAME_IS_JOB) + @javax.annotation.Nullable + private Boolean isJob; + + public static final String SERIALIZED_NAME_SPEC_DIGEST = "spec_digest"; + @SerializedName(SERIALIZED_NAME_SPEC_DIGEST) + @javax.annotation.Nullable + private String specDigest; + + public static final String SERIALIZED_NAME_IS_UPGRADING = "is_upgrading"; + @SerializedName(SERIALIZED_NAME_IS_UPGRADING) + @javax.annotation.Nullable + private Boolean isUpgrading; + + public static final String SERIALIZED_NAME_MANAGING_OBJECT_DOMAIN = "managing_object_domain"; + @SerializedName(SERIALIZED_NAME_MANAGING_OBJECT_DOMAIN) + @javax.annotation.Nullable + private String managingObjectDomain; + + public static final String SERIALIZED_NAME_MANAGING_OBJECT_NAME = "managing_object_name"; + @SerializedName(SERIALIZED_NAME_MANAGING_OBJECT_NAME) + @javax.annotation.Nullable + private String managingObjectName; + + public Service() { + } + + public Service( + Integer currentInstances, + Integer targetInstances, + String owner, + String dnsName, + OffsetDateTime createdOn, + OffsetDateTime updatedOn, + OffsetDateTime resumedOn, + OffsetDateTime suspendedOn, + String ownerRoleType, + Boolean isJob, + String specDigest, + Boolean isUpgrading, + String managingObjectDomain, + String managingObjectName + ) { + this(); + this.currentInstances = currentInstances; + this.targetInstances = targetInstances; + this.owner = owner; + this.dnsName = dnsName; + this.createdOn = createdOn; + this.updatedOn = updatedOn; + this.resumedOn = resumedOn; + this.suspendedOn = suspendedOn; + this.ownerRoleType = ownerRoleType; + this.isJob = isJob; + this.specDigest = specDigest; + this.isUpgrading = isUpgrading; + this.managingObjectDomain = managingObjectDomain; + this.managingObjectName = managingObjectName; + } + + public Service name(@javax.annotation.Nonnull String name) { + this.name = name; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return name + */ + @javax.annotation.Nonnull + public String getName() { + return name; + } + + public void setName(@javax.annotation.Nonnull String name) { + this.name = name; + } + + + public Service status(@javax.annotation.Nullable String status) { + this.status = status; + return this; + } + + /** + * The current status of the service. + * @return status + */ + @javax.annotation.Nullable + public String getStatus() { + return status; + } + + public void setStatus(@javax.annotation.Nullable String status) { + this.status = status; + } + + + public Service computePool(@javax.annotation.Nonnull String computePool) { + this.computePool = computePool; + return this; + } + + /** + * Specifies the name of the compute pool in your account on which to run the service. + * @return computePool + */ + @javax.annotation.Nonnull + public String getComputePool() { + return computePool; + } + + public void setComputePool(@javax.annotation.Nonnull String computePool) { + this.computePool = computePool; + } + + + public Service spec(@javax.annotation.Nonnull ServiceSpec spec) { + this.spec = spec; + return this; + } + + /** + * Get spec + * @return spec + */ + @javax.annotation.Nonnull + public ServiceSpec getSpec() { + return spec; + } + + public void setSpec(@javax.annotation.Nonnull ServiceSpec spec) { + this.spec = spec; + } + + + public Service externalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + this.externalAccessIntegrations = externalAccessIntegrations; + return this; + } + + public Service addExternalAccessIntegrationsItem(String externalAccessIntegrationsItem) { + if (this.externalAccessIntegrations == null) { + this.externalAccessIntegrations = new ArrayList<>(); + } + this.externalAccessIntegrations.add(externalAccessIntegrationsItem); + return this; + } + + /** + * Specifies the names of the external access integrations that allow your service to access external sites. + * @return externalAccessIntegrations + */ + @javax.annotation.Nullable + public List getExternalAccessIntegrations() { + return externalAccessIntegrations; + } + + public void setExternalAccessIntegrations(@javax.annotation.Nullable List externalAccessIntegrations) { + this.externalAccessIntegrations = externalAccessIntegrations; + } + + + public Service queryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + this.queryWarehouse = queryWarehouse; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return queryWarehouse + */ + @javax.annotation.Nullable + public String getQueryWarehouse() { + return queryWarehouse; + } + + public void setQueryWarehouse(@javax.annotation.Nullable String queryWarehouse) { + this.queryWarehouse = queryWarehouse; + } + + + public Service comment(@javax.annotation.Nullable String comment) { + this.comment = comment; + return this; + } + + /** + * Specifies a comment for the service. + * @return comment + */ + @javax.annotation.Nullable + public String getComment() { + return comment; + } + + public void setComment(@javax.annotation.Nullable String comment) { + this.comment = comment; + } + + + public Service isAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + this.isAsyncJob = isAsyncJob; + return this; + } + + /** + * True if the service is an async job service; false otherwise. + * @return isAsyncJob + */ + @javax.annotation.Nullable + public Boolean getIsAsyncJob() { + return isAsyncJob; + } + + public void setIsAsyncJob(@javax.annotation.Nullable Boolean isAsyncJob) { + this.isAsyncJob = isAsyncJob; + } + + + public Service autoResume(@javax.annotation.Nullable Boolean autoResume) { + this.autoResume = autoResume; + return this; + } + + /** + * Specifies whether to automatically resume a service when a service function or ingress is called. + * @return autoResume + */ + @javax.annotation.Nullable + public Boolean getAutoResume() { + return autoResume; + } + + public void setAutoResume(@javax.annotation.Nullable Boolean autoResume) { + this.autoResume = autoResume; + } + + + /** + * The current number of instances for the service. + * @return currentInstances + */ + @javax.annotation.Nullable + public Integer getCurrentInstances() { + return currentInstances; + } + + + + /** + * The target number of service instances that should be running as determined by Snowflake. + * @return targetInstances + */ + @javax.annotation.Nullable + public Integer getTargetInstances() { + return targetInstances; + } + + + + public Service minReadyInstances(@javax.annotation.Nullable Integer minReadyInstances) { + this.minReadyInstances = minReadyInstances; + return this; + } + + /** + * The minimum number of ready service instances to declare the service as READY. + * @return minReadyInstances + */ + @javax.annotation.Nullable + public Integer getMinReadyInstances() { + return minReadyInstances; + } + + public void setMinReadyInstances(@javax.annotation.Nullable Integer minReadyInstances) { + this.minReadyInstances = minReadyInstances; + } + + + public Service minInstances(@javax.annotation.Nullable Integer minInstances) { + this.minInstances = minInstances; + return this; + } + + /** + * Specifies the minimum number of service instances to run. + * @return minInstances + */ + @javax.annotation.Nullable + public Integer getMinInstances() { + return minInstances; + } + + public void setMinInstances(@javax.annotation.Nullable Integer minInstances) { + this.minInstances = minInstances; + } + + + public Service maxInstances(@javax.annotation.Nullable Integer maxInstances) { + this.maxInstances = maxInstances; + return this; + } + + /** + * Specifies the maximum number of service instances to run. + * @return maxInstances + */ + @javax.annotation.Nullable + public Integer getMaxInstances() { + return maxInstances; + } + + public void setMaxInstances(@javax.annotation.Nullable Integer maxInstances) { + this.maxInstances = maxInstances; + } + + + public Service databaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + + public Service schemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + public String getSchemaName() { + return schemaName; + } + + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + + /** + * Role that owns the service. + * @return owner + */ + @javax.annotation.Nullable + public String getOwner() { + return owner; + } + + + + /** + * Snowflake-assiged DNS name of the service. The DNS name enables service-to-service communications. + * @return dnsName + */ + @javax.annotation.Nullable + public String getDnsName() { + return dnsName; + } + + + + /** + * Timestamp when the service was created. + * @return createdOn + */ + @javax.annotation.Nullable + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * Timestamp when the service was last updated. + * @return updatedOn + */ + @javax.annotation.Nullable + public OffsetDateTime getUpdatedOn() { + return updatedOn; + } + + + + /** + * Timestamp when the service was last resumed. + * @return resumedOn + */ + @javax.annotation.Nullable + public OffsetDateTime getResumedOn() { + return resumedOn; + } + + + + /** + * Timestamp when the service was last suspended. + * @return suspendedOn + */ + @javax.annotation.Nullable + public OffsetDateTime getSuspendedOn() { + return suspendedOn; + } + + + + public Service autoSuspendSecs(@javax.annotation.Nullable Long autoSuspendSecs) { + this.autoSuspendSecs = autoSuspendSecs; + return this; + } + + /** + * Number of seconds of inactivity after which the service will be automatically suspended. The default value is 0 which represents the service will not be automatically suspended. + * @return autoSuspendSecs + */ + @javax.annotation.Nullable + public Long getAutoSuspendSecs() { + return autoSuspendSecs; + } + + public void setAutoSuspendSecs(@javax.annotation.Nullable Long autoSuspendSecs) { + this.autoSuspendSecs = autoSuspendSecs; + } + + + /** + * The role type of the service owner. + * @return ownerRoleType + */ + @javax.annotation.Nullable + public String getOwnerRoleType() { + return ownerRoleType; + } + + + + /** + * True if the service is a job service; false otherwise. + * @return isJob + */ + @javax.annotation.Nullable + public Boolean getIsJob() { + return isJob; + } + + + + /** + * The unique and immutable identifier representing the service spec content. + * @return specDigest + */ + @javax.annotation.Nullable + public String getSpecDigest() { + return specDigest; + } + + + + /** + * TRUE, if Snowflake is in the process of upgrading the service. + * @return isUpgrading + */ + @javax.annotation.Nullable + public Boolean getIsUpgrading() { + return isUpgrading; + } + + + + /** + * The domain of the managing object (for example, the domain of the notebook that manages the service). NULL if the service is not managed by a Snowflake entity. + * @return managingObjectDomain + */ + @javax.annotation.Nullable + public String getManagingObjectDomain() { + return managingObjectDomain; + } + + + + /** + * The name of the managing object (for example, the name of the notebook that manages the service). NULL if the service is not managed by a Snowflake entity. + * @return managingObjectName + */ + @javax.annotation.Nullable + public String getManagingObjectName() { + return managingObjectName; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Service service = (Service) o; + return Objects.equals(this.name, service.name) && + Objects.equals(this.status, service.status) && + Objects.equals(this.computePool, service.computePool) && + Objects.equals(this.spec, service.spec) && + Objects.equals(this.externalAccessIntegrations, service.externalAccessIntegrations) && + Objects.equals(this.queryWarehouse, service.queryWarehouse) && + Objects.equals(this.comment, service.comment) && + Objects.equals(this.isAsyncJob, service.isAsyncJob) && + Objects.equals(this.autoResume, service.autoResume) && + Objects.equals(this.currentInstances, service.currentInstances) && + Objects.equals(this.targetInstances, service.targetInstances) && + Objects.equals(this.minReadyInstances, service.minReadyInstances) && + Objects.equals(this.minInstances, service.minInstances) && + Objects.equals(this.maxInstances, service.maxInstances) && + Objects.equals(this.databaseName, service.databaseName) && + Objects.equals(this.schemaName, service.schemaName) && + Objects.equals(this.owner, service.owner) && + Objects.equals(this.dnsName, service.dnsName) && + Objects.equals(this.createdOn, service.createdOn) && + Objects.equals(this.updatedOn, service.updatedOn) && + Objects.equals(this.resumedOn, service.resumedOn) && + Objects.equals(this.suspendedOn, service.suspendedOn) && + Objects.equals(this.autoSuspendSecs, service.autoSuspendSecs) && + Objects.equals(this.ownerRoleType, service.ownerRoleType) && + Objects.equals(this.isJob, service.isJob) && + Objects.equals(this.specDigest, service.specDigest) && + Objects.equals(this.isUpgrading, service.isUpgrading) && + Objects.equals(this.managingObjectDomain, service.managingObjectDomain) && + Objects.equals(this.managingObjectName, service.managingObjectName); + } + + @Override + public int hashCode() { + return Objects.hash(name, status, computePool, spec, externalAccessIntegrations, queryWarehouse, comment, isAsyncJob, autoResume, currentInstances, targetInstances, minReadyInstances, minInstances, maxInstances, databaseName, schemaName, owner, dnsName, createdOn, updatedOn, resumedOn, suspendedOn, autoSuspendSecs, ownerRoleType, isJob, specDigest, isUpgrading, managingObjectDomain, managingObjectName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Service {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" computePool: ").append(toIndentedString(computePool)).append("\n"); + sb.append(" spec: ").append(toIndentedString(spec)).append("\n"); + sb.append(" externalAccessIntegrations: ").append(toIndentedString(externalAccessIntegrations)).append("\n"); + sb.append(" queryWarehouse: ").append(toIndentedString(queryWarehouse)).append("\n"); + sb.append(" comment: ").append(toIndentedString(comment)).append("\n"); + sb.append(" isAsyncJob: ").append(toIndentedString(isAsyncJob)).append("\n"); + sb.append(" autoResume: ").append(toIndentedString(autoResume)).append("\n"); + sb.append(" currentInstances: ").append(toIndentedString(currentInstances)).append("\n"); + sb.append(" targetInstances: ").append(toIndentedString(targetInstances)).append("\n"); + sb.append(" minReadyInstances: ").append(toIndentedString(minReadyInstances)).append("\n"); + sb.append(" minInstances: ").append(toIndentedString(minInstances)).append("\n"); + sb.append(" maxInstances: ").append(toIndentedString(maxInstances)).append("\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" owner: ").append(toIndentedString(owner)).append("\n"); + sb.append(" dnsName: ").append(toIndentedString(dnsName)).append("\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" updatedOn: ").append(toIndentedString(updatedOn)).append("\n"); + sb.append(" resumedOn: ").append(toIndentedString(resumedOn)).append("\n"); + sb.append(" suspendedOn: ").append(toIndentedString(suspendedOn)).append("\n"); + sb.append(" autoSuspendSecs: ").append(toIndentedString(autoSuspendSecs)).append("\n"); + sb.append(" ownerRoleType: ").append(toIndentedString(ownerRoleType)).append("\n"); + sb.append(" isJob: ").append(toIndentedString(isJob)).append("\n"); + sb.append(" specDigest: ").append(toIndentedString(specDigest)).append("\n"); + sb.append(" isUpgrading: ").append(toIndentedString(isUpgrading)).append("\n"); + sb.append(" managingObjectDomain: ").append(toIndentedString(managingObjectDomain)).append("\n"); + sb.append(" managingObjectName: ").append(toIndentedString(managingObjectName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("name", "status", "compute_pool", "spec", "external_access_integrations", "query_warehouse", "comment", "is_async_job", "auto_resume", "current_instances", "target_instances", "min_ready_instances", "min_instances", "max_instances", "database_name", "schema_name", "owner", "dns_name", "created_on", "updated_on", "resumed_on", "suspended_on", "auto_suspend_secs", "owner_role_type", "is_job", "spec_digest", "is_upgrading", "managing_object_domain", "managing_object_name")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("name", "compute_pool", "spec")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to Service + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!Service.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in Service is not found in the empty JSON string", Service.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!Service.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `Service` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : Service.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if (!jsonObj.get("name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("name").toString())); + } + if ((jsonObj.get("status") != null && !jsonObj.get("status").isJsonNull()) && !jsonObj.get("status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("status").toString())); + } + if (!jsonObj.get("compute_pool").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `compute_pool` to be a primitive type in the JSON string but got `%s`", jsonObj.get("compute_pool").toString())); + } + // validate the required field `spec` + ServiceSpec.validateJsonElement(jsonObj.get("spec")); + // ensure the optional json data is an array if present + if (jsonObj.get("external_access_integrations") != null && !jsonObj.get("external_access_integrations").isJsonNull() && !jsonObj.get("external_access_integrations").isJsonArray()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `external_access_integrations` to be an array in the JSON string but got `%s`", jsonObj.get("external_access_integrations").toString())); + } + if ((jsonObj.get("query_warehouse") != null && !jsonObj.get("query_warehouse").isJsonNull()) && !jsonObj.get("query_warehouse").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `query_warehouse` to be a primitive type in the JSON string but got `%s`", jsonObj.get("query_warehouse").toString())); + } + if ((jsonObj.get("comment") != null && !jsonObj.get("comment").isJsonNull()) && !jsonObj.get("comment").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `comment` to be a primitive type in the JSON string but got `%s`", jsonObj.get("comment").toString())); + } + if ((jsonObj.get("database_name") != null && !jsonObj.get("database_name").isJsonNull()) && !jsonObj.get("database_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `database_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("database_name").toString())); + } + if ((jsonObj.get("schema_name") != null && !jsonObj.get("schema_name").isJsonNull()) && !jsonObj.get("schema_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `schema_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("schema_name").toString())); + } + if ((jsonObj.get("owner") != null && !jsonObj.get("owner").isJsonNull()) && !jsonObj.get("owner").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `owner` to be a primitive type in the JSON string but got `%s`", jsonObj.get("owner").toString())); + } + if ((jsonObj.get("dns_name") != null && !jsonObj.get("dns_name").isJsonNull()) && !jsonObj.get("dns_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `dns_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("dns_name").toString())); + } + if ((jsonObj.get("owner_role_type") != null && !jsonObj.get("owner_role_type").isJsonNull()) && !jsonObj.get("owner_role_type").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `owner_role_type` to be a primitive type in the JSON string but got `%s`", jsonObj.get("owner_role_type").toString())); + } + if ((jsonObj.get("spec_digest") != null && !jsonObj.get("spec_digest").isJsonNull()) && !jsonObj.get("spec_digest").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `spec_digest` to be a primitive type in the JSON string but got `%s`", jsonObj.get("spec_digest").toString())); + } + if ((jsonObj.get("managing_object_domain") != null && !jsonObj.get("managing_object_domain").isJsonNull()) && !jsonObj.get("managing_object_domain").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `managing_object_domain` to be a primitive type in the JSON string but got `%s`", jsonObj.get("managing_object_domain").toString())); + } + if ((jsonObj.get("managing_object_name") != null && !jsonObj.get("managing_object_name").isJsonNull()) && !jsonObj.get("managing_object_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `managing_object_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("managing_object_name").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!Service.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'Service' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(Service.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, Service value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public Service read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of Service given an JSON string + * + * @param jsonString JSON string + * @return An instance of Service + * @throws IOException if the JSON string is invalid with respect to Service + */ + public static Service fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, Service.class); + } + + /** + * Convert an instance of Service to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java new file mode 100644 index 00000000..b8f95a96 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceContainer.java @@ -0,0 +1,498 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceContainer + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceContainer { + public static final String SERIALIZED_NAME_DATABASE_NAME = "database_name"; + @SerializedName(SERIALIZED_NAME_DATABASE_NAME) + @javax.annotation.Nullable + private String databaseName; + + public static final String SERIALIZED_NAME_SCHEMA_NAME = "schema_name"; + @SerializedName(SERIALIZED_NAME_SCHEMA_NAME) + @javax.annotation.Nullable + private String schemaName; + + public static final String SERIALIZED_NAME_SERVICE_NAME = "service_name"; + @SerializedName(SERIALIZED_NAME_SERVICE_NAME) + @javax.annotation.Nullable + private String serviceName; + + public static final String SERIALIZED_NAME_SERVICE_STATUS = "service_status"; + @SerializedName(SERIALIZED_NAME_SERVICE_STATUS) + @javax.annotation.Nullable + private String serviceStatus; + + public static final String SERIALIZED_NAME_INSTANCE_ID = "instance_id"; + @SerializedName(SERIALIZED_NAME_INSTANCE_ID) + @javax.annotation.Nullable + private String instanceId; + + public static final String SERIALIZED_NAME_INSTANCE_STATUS = "instance_status"; + @SerializedName(SERIALIZED_NAME_INSTANCE_STATUS) + @javax.annotation.Nullable + private String instanceStatus; + + public static final String SERIALIZED_NAME_CONTAINER_NAME = "container_name"; + @SerializedName(SERIALIZED_NAME_CONTAINER_NAME) + @javax.annotation.Nullable + private String containerName; + + public static final String SERIALIZED_NAME_STATUS = "status"; + @SerializedName(SERIALIZED_NAME_STATUS) + @javax.annotation.Nullable + private String status; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_IMAGE_NAME = "image_name"; + @SerializedName(SERIALIZED_NAME_IMAGE_NAME) + @javax.annotation.Nullable + private String imageName; + + public static final String SERIALIZED_NAME_IMAGE_DIGEST = "image_digest"; + @SerializedName(SERIALIZED_NAME_IMAGE_DIGEST) + @javax.annotation.Nullable + private String imageDigest; + + public static final String SERIALIZED_NAME_RESTART_COUNT = "restart_count"; + @SerializedName(SERIALIZED_NAME_RESTART_COUNT) + @javax.annotation.Nullable + private Integer restartCount; + + public static final String SERIALIZED_NAME_START_TIME = "start_time"; + @SerializedName(SERIALIZED_NAME_START_TIME) + @javax.annotation.Nullable + private String startTime; + + public ServiceContainer() { + } + + public ServiceContainer( + String serviceStatus, + String instanceId, + String instanceStatus, + String containerName, + String status, + String message, + String imageName, + String imageDigest, + Integer restartCount, + String startTime + ) { + this(); + this.serviceStatus = serviceStatus; + this.instanceId = instanceId; + this.instanceStatus = instanceStatus; + this.containerName = containerName; + this.status = status; + this.message = message; + this.imageName = imageName; + this.imageDigest = imageDigest; + this.restartCount = restartCount; + this.startTime = startTime; + } + + public ServiceContainer databaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + + public ServiceContainer schemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + public String getSchemaName() { + return schemaName; + } + + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + + public ServiceContainer serviceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return serviceName + */ + @javax.annotation.Nullable + public String getServiceName() { + return serviceName; + } + + public void setServiceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + } + + + /** + * The current status of the service. + * @return serviceStatus + */ + @javax.annotation.Nullable + public String getServiceStatus() { + return serviceStatus; + } + + + + /** + * ID of the service instance (this is the index of the service instance starting from 0). + * @return instanceId + */ + @javax.annotation.Nullable + public String getInstanceId() { + return instanceId; + } + + + + /** + * The current status of the service instance. + * @return instanceStatus + */ + @javax.annotation.Nullable + public String getInstanceStatus() { + return instanceStatus; + } + + + + /** + * Name of the container. + * @return containerName + */ + @javax.annotation.Nullable + public String getContainerName() { + return containerName; + } + + + + /** + * Service container status. + * @return status + */ + @javax.annotation.Nullable + public String getStatus() { + return status; + } + + + + /** + * Additional clarification about status. + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + + + /** + * Image name used to create the service container. + * @return imageName + */ + @javax.annotation.Nullable + public String getImageName() { + return imageName; + } + + + + /** + * The unique and immutable identifier representing the image content. + * @return imageDigest + */ + @javax.annotation.Nullable + public String getImageDigest() { + return imageDigest; + } + + + + /** + * Number of times Snowflake restarted the service. + * @return restartCount + */ + @javax.annotation.Nullable + public Integer getRestartCount() { + return restartCount; + } + + + + /** + * Date and time when the container started. + * @return startTime + */ + @javax.annotation.Nullable + public String getStartTime() { + return startTime; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceContainer serviceContainer = (ServiceContainer) o; + return Objects.equals(this.databaseName, serviceContainer.databaseName) && + Objects.equals(this.schemaName, serviceContainer.schemaName) && + Objects.equals(this.serviceName, serviceContainer.serviceName) && + Objects.equals(this.serviceStatus, serviceContainer.serviceStatus) && + Objects.equals(this.instanceId, serviceContainer.instanceId) && + Objects.equals(this.instanceStatus, serviceContainer.instanceStatus) && + Objects.equals(this.containerName, serviceContainer.containerName) && + Objects.equals(this.status, serviceContainer.status) && + Objects.equals(this.message, serviceContainer.message) && + Objects.equals(this.imageName, serviceContainer.imageName) && + Objects.equals(this.imageDigest, serviceContainer.imageDigest) && + Objects.equals(this.restartCount, serviceContainer.restartCount) && + Objects.equals(this.startTime, serviceContainer.startTime); + } + + @Override + public int hashCode() { + return Objects.hash(databaseName, schemaName, serviceName, serviceStatus, instanceId, instanceStatus, containerName, status, message, imageName, imageDigest, restartCount, startTime); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceContainer {\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" serviceName: ").append(toIndentedString(serviceName)).append("\n"); + sb.append(" serviceStatus: ").append(toIndentedString(serviceStatus)).append("\n"); + sb.append(" instanceId: ").append(toIndentedString(instanceId)).append("\n"); + sb.append(" instanceStatus: ").append(toIndentedString(instanceStatus)).append("\n"); + sb.append(" containerName: ").append(toIndentedString(containerName)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" imageName: ").append(toIndentedString(imageName)).append("\n"); + sb.append(" imageDigest: ").append(toIndentedString(imageDigest)).append("\n"); + sb.append(" restartCount: ").append(toIndentedString(restartCount)).append("\n"); + sb.append(" startTime: ").append(toIndentedString(startTime)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("database_name", "schema_name", "service_name", "service_status", "instance_id", "instance_status", "container_name", "status", "message", "image_name", "image_digest", "restart_count", "start_time")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceContainer + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceContainer.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceContainer is not found in the empty JSON string", ServiceContainer.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceContainer.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceContainer` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("database_name") != null && !jsonObj.get("database_name").isJsonNull()) && !jsonObj.get("database_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `database_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("database_name").toString())); + } + if ((jsonObj.get("schema_name") != null && !jsonObj.get("schema_name").isJsonNull()) && !jsonObj.get("schema_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `schema_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("schema_name").toString())); + } + if ((jsonObj.get("service_name") != null && !jsonObj.get("service_name").isJsonNull()) && !jsonObj.get("service_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `service_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("service_name").toString())); + } + if ((jsonObj.get("service_status") != null && !jsonObj.get("service_status").isJsonNull()) && !jsonObj.get("service_status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `service_status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("service_status").toString())); + } + if ((jsonObj.get("instance_id") != null && !jsonObj.get("instance_id").isJsonNull()) && !jsonObj.get("instance_id").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `instance_id` to be a primitive type in the JSON string but got `%s`", jsonObj.get("instance_id").toString())); + } + if ((jsonObj.get("instance_status") != null && !jsonObj.get("instance_status").isJsonNull()) && !jsonObj.get("instance_status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `instance_status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("instance_status").toString())); + } + if ((jsonObj.get("container_name") != null && !jsonObj.get("container_name").isJsonNull()) && !jsonObj.get("container_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `container_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("container_name").toString())); + } + if ((jsonObj.get("status") != null && !jsonObj.get("status").isJsonNull()) && !jsonObj.get("status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("status").toString())); + } + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if ((jsonObj.get("image_name") != null && !jsonObj.get("image_name").isJsonNull()) && !jsonObj.get("image_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `image_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("image_name").toString())); + } + if ((jsonObj.get("image_digest") != null && !jsonObj.get("image_digest").isJsonNull()) && !jsonObj.get("image_digest").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `image_digest` to be a primitive type in the JSON string but got `%s`", jsonObj.get("image_digest").toString())); + } + if ((jsonObj.get("start_time") != null && !jsonObj.get("start_time").isJsonNull()) && !jsonObj.get("start_time").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `start_time` to be a primitive type in the JSON string but got `%s`", jsonObj.get("start_time").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceContainer.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceContainer' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceContainer.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceContainer value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceContainer read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceContainer given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceContainer + * @throws IOException if the JSON string is invalid with respect to ServiceContainer + */ + public static ServiceContainer fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceContainer.class); + } + + /** + * Convert an instance of ServiceContainer to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java new file mode 100644 index 00000000..1538ea5f --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceEndpoint.java @@ -0,0 +1,346 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceEndpoint + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceEndpoint { + public static final String SERIALIZED_NAME_NAME = "name"; + @SerializedName(SERIALIZED_NAME_NAME) + @javax.annotation.Nullable + private String name; + + public static final String SERIALIZED_NAME_PORT = "port"; + @SerializedName(SERIALIZED_NAME_PORT) + @javax.annotation.Nullable + private Integer port; + + public static final String SERIALIZED_NAME_PORT_RANGE = "portRange"; + @SerializedName(SERIALIZED_NAME_PORT_RANGE) + @javax.annotation.Nullable + private String portRange; + + public static final String SERIALIZED_NAME_PROTOCOL = "protocol"; + @SerializedName(SERIALIZED_NAME_PROTOCOL) + @javax.annotation.Nullable + private String protocol = "HTTP"; + + public static final String SERIALIZED_NAME_IS_PUBLIC = "is_public"; + @SerializedName(SERIALIZED_NAME_IS_PUBLIC) + @javax.annotation.Nullable + private Boolean isPublic = false; + + public static final String SERIALIZED_NAME_INGRESS_URL = "ingress_url"; + @SerializedName(SERIALIZED_NAME_INGRESS_URL) + @javax.annotation.Nullable + private String ingressUrl; + + public ServiceEndpoint() { + } + + public ServiceEndpoint( + String ingressUrl + ) { + this(); + this.ingressUrl = ingressUrl; + } + + public ServiceEndpoint name(@javax.annotation.Nullable String name) { + this.name = name; + return this; + } + + /** + * User-friendly endpoint name that represents the corresponding port. + * @return name + */ + @javax.annotation.Nullable + public String getName() { + return name; + } + + public void setName(@javax.annotation.Nullable String name) { + this.name = name; + } + + + public ServiceEndpoint port(@javax.annotation.Nullable Integer port) { + this.port = port; + return this; + } + + /** + * The network port the service is listening on. NULL, when portRange is specified. + * @return port + */ + @javax.annotation.Nullable + public Integer getPort() { + return port; + } + + public void setPort(@javax.annotation.Nullable Integer port) { + this.port = port; + } + + + public ServiceEndpoint portRange(@javax.annotation.Nullable String portRange) { + this.portRange = portRange; + return this; + } + + /** + * The network port range the service is listening on. NULL, when port is specified. + * @return portRange + */ + @javax.annotation.Nullable + public String getPortRange() { + return portRange; + } + + public void setPortRange(@javax.annotation.Nullable String portRange) { + this.portRange = portRange; + } + + + public ServiceEndpoint protocol(@javax.annotation.Nullable String protocol) { + this.protocol = protocol; + return this; + } + + /** + * Supported network protocol (TCP, HTTP, or HTTPS). + * @return protocol + */ + @javax.annotation.Nullable + public String getProtocol() { + return protocol; + } + + public void setProtocol(@javax.annotation.Nullable String protocol) { + this.protocol = protocol; + } + + + public ServiceEndpoint isPublic(@javax.annotation.Nullable Boolean isPublic) { + this.isPublic = isPublic; + return this; + } + + /** + * True, if the endpoint is public, accessible from internet. + * @return isPublic + */ + @javax.annotation.Nullable + public Boolean getIsPublic() { + return isPublic; + } + + public void setIsPublic(@javax.annotation.Nullable Boolean isPublic) { + this.isPublic = isPublic; + } + + + /** + * Endpoint URL accessible from the internet. + * @return ingressUrl + */ + @javax.annotation.Nullable + public String getIngressUrl() { + return ingressUrl; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceEndpoint serviceEndpoint = (ServiceEndpoint) o; + return Objects.equals(this.name, serviceEndpoint.name) && + Objects.equals(this.port, serviceEndpoint.port) && + Objects.equals(this.portRange, serviceEndpoint.portRange) && + Objects.equals(this.protocol, serviceEndpoint.protocol) && + Objects.equals(this.isPublic, serviceEndpoint.isPublic) && + Objects.equals(this.ingressUrl, serviceEndpoint.ingressUrl); + } + + @Override + public int hashCode() { + return Objects.hash(name, port, portRange, protocol, isPublic, ingressUrl); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceEndpoint {\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" port: ").append(toIndentedString(port)).append("\n"); + sb.append(" portRange: ").append(toIndentedString(portRange)).append("\n"); + sb.append(" protocol: ").append(toIndentedString(protocol)).append("\n"); + sb.append(" isPublic: ").append(toIndentedString(isPublic)).append("\n"); + sb.append(" ingressUrl: ").append(toIndentedString(ingressUrl)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("name", "port", "portRange", "protocol", "is_public", "ingress_url")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceEndpoint + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceEndpoint.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceEndpoint is not found in the empty JSON string", ServiceEndpoint.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceEndpoint.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceEndpoint` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("name") != null && !jsonObj.get("name").isJsonNull()) && !jsonObj.get("name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("name").toString())); + } + if ((jsonObj.get("portRange") != null && !jsonObj.get("portRange").isJsonNull()) && !jsonObj.get("portRange").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `portRange` to be a primitive type in the JSON string but got `%s`", jsonObj.get("portRange").toString())); + } + if ((jsonObj.get("protocol") != null && !jsonObj.get("protocol").isJsonNull()) && !jsonObj.get("protocol").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `protocol` to be a primitive type in the JSON string but got `%s`", jsonObj.get("protocol").toString())); + } + if ((jsonObj.get("ingress_url") != null && !jsonObj.get("ingress_url").isJsonNull()) && !jsonObj.get("ingress_url").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `ingress_url` to be a primitive type in the JSON string but got `%s`", jsonObj.get("ingress_url").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceEndpoint.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceEndpoint' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceEndpoint.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceEndpoint value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceEndpoint read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceEndpoint given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceEndpoint + * @throws IOException if the JSON string is invalid with respect to ServiceEndpoint + */ + public static ServiceEndpoint fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceEndpoint.class); + } + + /** + * Convert an instance of ServiceEndpoint to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java new file mode 100644 index 00000000..fdc8de6c --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceInstance.java @@ -0,0 +1,409 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceInstance + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceInstance { + public static final String SERIALIZED_NAME_DATABASE_NAME = "database_name"; + @SerializedName(SERIALIZED_NAME_DATABASE_NAME) + @javax.annotation.Nullable + private String databaseName; + + public static final String SERIALIZED_NAME_SCHEMA_NAME = "schema_name"; + @SerializedName(SERIALIZED_NAME_SCHEMA_NAME) + @javax.annotation.Nullable + private String schemaName; + + public static final String SERIALIZED_NAME_SERVICE_NAME = "service_name"; + @SerializedName(SERIALIZED_NAME_SERVICE_NAME) + @javax.annotation.Nullable + private String serviceName; + + public static final String SERIALIZED_NAME_SERVICE_STATUS = "service_status"; + @SerializedName(SERIALIZED_NAME_SERVICE_STATUS) + @javax.annotation.Nullable + private String serviceStatus; + + public static final String SERIALIZED_NAME_INSTANCE_ID = "instance_id"; + @SerializedName(SERIALIZED_NAME_INSTANCE_ID) + @javax.annotation.Nullable + private String instanceId; + + public static final String SERIALIZED_NAME_STATUS = "status"; + @SerializedName(SERIALIZED_NAME_STATUS) + @javax.annotation.Nullable + private String status; + + public static final String SERIALIZED_NAME_SPEC_DIGEST = "spec_digest"; + @SerializedName(SERIALIZED_NAME_SPEC_DIGEST) + @javax.annotation.Nullable + private String specDigest; + + public static final String SERIALIZED_NAME_CREATION_TIME = "creation_time"; + @SerializedName(SERIALIZED_NAME_CREATION_TIME) + @javax.annotation.Nullable + private String creationTime; + + public static final String SERIALIZED_NAME_START_TIME = "start_time"; + @SerializedName(SERIALIZED_NAME_START_TIME) + @javax.annotation.Nullable + private String startTime; + + public ServiceInstance() { + } + + public ServiceInstance( + String serviceStatus, + String instanceId, + String status, + String specDigest, + String creationTime, + String startTime + ) { + this(); + this.serviceStatus = serviceStatus; + this.instanceId = instanceId; + this.status = status; + this.specDigest = specDigest; + this.creationTime = creationTime; + this.startTime = startTime; + } + + public ServiceInstance databaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return databaseName + */ + @javax.annotation.Nullable + public String getDatabaseName() { + return databaseName; + } + + public void setDatabaseName(@javax.annotation.Nullable String databaseName) { + this.databaseName = databaseName; + } + + + public ServiceInstance schemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return schemaName + */ + @javax.annotation.Nullable + public String getSchemaName() { + return schemaName; + } + + public void setSchemaName(@javax.annotation.Nullable String schemaName) { + this.schemaName = schemaName; + } + + + public ServiceInstance serviceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + return this; + } + + /** + * A Snowflake object identifier. If the identifier contains spaces or special characters, the entire string must be enclosed in double quotes. Identifiers enclosed in double quotes are also case-sensitive. + * @return serviceName + */ + @javax.annotation.Nullable + public String getServiceName() { + return serviceName; + } + + public void setServiceName(@javax.annotation.Nullable String serviceName) { + this.serviceName = serviceName; + } + + + /** + * The current status of the service. + * @return serviceStatus + */ + @javax.annotation.Nullable + public String getServiceStatus() { + return serviceStatus; + } + + + + /** + * ID of the service instance (this is the index of the service instance starting from 0). + * @return instanceId + */ + @javax.annotation.Nullable + public String getInstanceId() { + return instanceId; + } + + + + /** + * The current status of the service instance. + * @return status + */ + @javax.annotation.Nullable + public String getStatus() { + return status; + } + + + + /** + * The unique and immutable identifier that represents the service specification content. + * @return specDigest + */ + @javax.annotation.Nullable + public String getSpecDigest() { + return specDigest; + } + + + + /** + * The time when Snowflake started creating the service instance. + * @return creationTime + */ + @javax.annotation.Nullable + public String getCreationTime() { + return creationTime; + } + + + + /** + * The time when Snowflake acknowledged the service instance is running on a node. + * @return startTime + */ + @javax.annotation.Nullable + public String getStartTime() { + return startTime; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceInstance serviceInstance = (ServiceInstance) o; + return Objects.equals(this.databaseName, serviceInstance.databaseName) && + Objects.equals(this.schemaName, serviceInstance.schemaName) && + Objects.equals(this.serviceName, serviceInstance.serviceName) && + Objects.equals(this.serviceStatus, serviceInstance.serviceStatus) && + Objects.equals(this.instanceId, serviceInstance.instanceId) && + Objects.equals(this.status, serviceInstance.status) && + Objects.equals(this.specDigest, serviceInstance.specDigest) && + Objects.equals(this.creationTime, serviceInstance.creationTime) && + Objects.equals(this.startTime, serviceInstance.startTime); + } + + @Override + public int hashCode() { + return Objects.hash(databaseName, schemaName, serviceName, serviceStatus, instanceId, status, specDigest, creationTime, startTime); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceInstance {\n"); + sb.append(" databaseName: ").append(toIndentedString(databaseName)).append("\n"); + sb.append(" schemaName: ").append(toIndentedString(schemaName)).append("\n"); + sb.append(" serviceName: ").append(toIndentedString(serviceName)).append("\n"); + sb.append(" serviceStatus: ").append(toIndentedString(serviceStatus)).append("\n"); + sb.append(" instanceId: ").append(toIndentedString(instanceId)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" specDigest: ").append(toIndentedString(specDigest)).append("\n"); + sb.append(" creationTime: ").append(toIndentedString(creationTime)).append("\n"); + sb.append(" startTime: ").append(toIndentedString(startTime)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("database_name", "schema_name", "service_name", "service_status", "instance_id", "status", "spec_digest", "creation_time", "start_time")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceInstance + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceInstance.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceInstance is not found in the empty JSON string", ServiceInstance.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceInstance.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceInstance` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("database_name") != null && !jsonObj.get("database_name").isJsonNull()) && !jsonObj.get("database_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `database_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("database_name").toString())); + } + if ((jsonObj.get("schema_name") != null && !jsonObj.get("schema_name").isJsonNull()) && !jsonObj.get("schema_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `schema_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("schema_name").toString())); + } + if ((jsonObj.get("service_name") != null && !jsonObj.get("service_name").isJsonNull()) && !jsonObj.get("service_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `service_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("service_name").toString())); + } + if ((jsonObj.get("service_status") != null && !jsonObj.get("service_status").isJsonNull()) && !jsonObj.get("service_status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `service_status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("service_status").toString())); + } + if ((jsonObj.get("instance_id") != null && !jsonObj.get("instance_id").isJsonNull()) && !jsonObj.get("instance_id").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `instance_id` to be a primitive type in the JSON string but got `%s`", jsonObj.get("instance_id").toString())); + } + if ((jsonObj.get("status") != null && !jsonObj.get("status").isJsonNull()) && !jsonObj.get("status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("status").toString())); + } + if ((jsonObj.get("spec_digest") != null && !jsonObj.get("spec_digest").isJsonNull()) && !jsonObj.get("spec_digest").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `spec_digest` to be a primitive type in the JSON string but got `%s`", jsonObj.get("spec_digest").toString())); + } + if ((jsonObj.get("creation_time") != null && !jsonObj.get("creation_time").isJsonNull()) && !jsonObj.get("creation_time").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `creation_time` to be a primitive type in the JSON string but got `%s`", jsonObj.get("creation_time").toString())); + } + if ((jsonObj.get("start_time") != null && !jsonObj.get("start_time").isJsonNull()) && !jsonObj.get("start_time").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `start_time` to be a primitive type in the JSON string but got `%s`", jsonObj.get("start_time").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceInstance.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceInstance' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceInstance.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceInstance value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceInstance read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceInstance given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceInstance + * @throws IOException if the JSON string is invalid with respect to ServiceInstance + */ + public static ServiceInstance fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceInstance.class); + } + + /** + * Convert an instance of ServiceInstance to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java new file mode 100644 index 00000000..2e346af4 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRole.java @@ -0,0 +1,251 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceRole + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceRole { + public static final String SERIALIZED_NAME_CREATED_ON = "created_on"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String SERIALIZED_NAME_NAME = "name"; + @SerializedName(SERIALIZED_NAME_NAME) + @javax.annotation.Nullable + private String name; + + public static final String SERIALIZED_NAME_COMMENT = "comment"; + @SerializedName(SERIALIZED_NAME_COMMENT) + @javax.annotation.Nullable + private String comment; + + public ServiceRole() { + } + + public ServiceRole( + OffsetDateTime createdOn, + String name, + String comment + ) { + this(); + this.createdOn = createdOn; + this.name = name; + this.comment = comment; + } + + /** + * Date and time when the service role was created + * @return createdOn + */ + @javax.annotation.Nullable + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * Service role name + * @return name + */ + @javax.annotation.Nullable + public String getName() { + return name; + } + + + + /** + * Comment, if any, for the service role + * @return comment + */ + @javax.annotation.Nullable + public String getComment() { + return comment; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceRole serviceRole = (ServiceRole) o; + return Objects.equals(this.createdOn, serviceRole.createdOn) && + Objects.equals(this.name, serviceRole.name) && + Objects.equals(this.comment, serviceRole.comment); + } + + @Override + public int hashCode() { + return Objects.hash(createdOn, name, comment); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceRole {\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" comment: ").append(toIndentedString(comment)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("created_on", "name", "comment")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceRole + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceRole.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceRole is not found in the empty JSON string", ServiceRole.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceRole.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceRole` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("name") != null && !jsonObj.get("name").isJsonNull()) && !jsonObj.get("name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("name").toString())); + } + if ((jsonObj.get("comment") != null && !jsonObj.get("comment").isJsonNull()) && !jsonObj.get("comment").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `comment` to be a primitive type in the JSON string but got `%s`", jsonObj.get("comment").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceRole.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceRole' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceRole.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceRole value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceRole read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceRole given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceRole + * @throws IOException if the JSON string is invalid with respect to ServiceRole + */ + public static ServiceRole fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceRole.class); + } + + /** + * Convert an instance of ServiceRole to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java new file mode 100644 index 00000000..0535052b --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceRoleGrantTo.java @@ -0,0 +1,320 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceRoleGrantTo + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceRoleGrantTo { + public static final String SERIALIZED_NAME_CREATED_ON = "created_on"; + @SerializedName(SERIALIZED_NAME_CREATED_ON) + @javax.annotation.Nullable + private OffsetDateTime createdOn; + + public static final String SERIALIZED_NAME_PRIVILEGE = "privilege"; + @SerializedName(SERIALIZED_NAME_PRIVILEGE) + @javax.annotation.Nullable + private String privilege; + + public static final String SERIALIZED_NAME_GRANTED_ON = "granted_on"; + @SerializedName(SERIALIZED_NAME_GRANTED_ON) + @javax.annotation.Nullable + private String grantedOn; + + public static final String SERIALIZED_NAME_NAME = "name"; + @SerializedName(SERIALIZED_NAME_NAME) + @javax.annotation.Nullable + private String name; + + public static final String SERIALIZED_NAME_GRANTED_TO = "granted_to"; + @SerializedName(SERIALIZED_NAME_GRANTED_TO) + @javax.annotation.Nullable + private String grantedTo; + + public static final String SERIALIZED_NAME_GRANTEE_NAME = "grantee_name"; + @SerializedName(SERIALIZED_NAME_GRANTEE_NAME) + @javax.annotation.Nullable + private String granteeName; + + public ServiceRoleGrantTo() { + } + + public ServiceRoleGrantTo( + OffsetDateTime createdOn, + String privilege, + String grantedOn, + String name, + String grantedTo, + String granteeName + ) { + this(); + this.createdOn = createdOn; + this.privilege = privilege; + this.grantedOn = grantedOn; + this.name = name; + this.grantedTo = grantedTo; + this.granteeName = granteeName; + } + + /** + * Date and time when the grant was created + * @return createdOn + */ + @javax.annotation.Nullable + public OffsetDateTime getCreatedOn() { + return createdOn; + } + + + + /** + * The name of the privilege + * @return privilege + */ + @javax.annotation.Nullable + public String getPrivilege() { + return privilege; + } + + + + /** + * The type of of the securable + * @return grantedOn + */ + @javax.annotation.Nullable + public String getGrantedOn() { + return grantedOn; + } + + + + /** + * The name of the securable + * @return name + */ + @javax.annotation.Nullable + public String getName() { + return name; + } + + + + /** + * The type of the grantee + * @return grantedTo + */ + @javax.annotation.Nullable + public String getGrantedTo() { + return grantedTo; + } + + + + /** + * The name of the grantee + * @return granteeName + */ + @javax.annotation.Nullable + public String getGranteeName() { + return granteeName; + } + + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceRoleGrantTo serviceRoleGrantTo = (ServiceRoleGrantTo) o; + return Objects.equals(this.createdOn, serviceRoleGrantTo.createdOn) && + Objects.equals(this.privilege, serviceRoleGrantTo.privilege) && + Objects.equals(this.grantedOn, serviceRoleGrantTo.grantedOn) && + Objects.equals(this.name, serviceRoleGrantTo.name) && + Objects.equals(this.grantedTo, serviceRoleGrantTo.grantedTo) && + Objects.equals(this.granteeName, serviceRoleGrantTo.granteeName); + } + + @Override + public int hashCode() { + return Objects.hash(createdOn, privilege, grantedOn, name, grantedTo, granteeName); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceRoleGrantTo {\n"); + sb.append(" createdOn: ").append(toIndentedString(createdOn)).append("\n"); + sb.append(" privilege: ").append(toIndentedString(privilege)).append("\n"); + sb.append(" grantedOn: ").append(toIndentedString(grantedOn)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" grantedTo: ").append(toIndentedString(grantedTo)).append("\n"); + sb.append(" granteeName: ").append(toIndentedString(granteeName)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("created_on", "privilege", "granted_on", "name", "granted_to", "grantee_name")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceRoleGrantTo + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceRoleGrantTo.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceRoleGrantTo is not found in the empty JSON string", ServiceRoleGrantTo.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceRoleGrantTo.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceRoleGrantTo` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("privilege") != null && !jsonObj.get("privilege").isJsonNull()) && !jsonObj.get("privilege").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `privilege` to be a primitive type in the JSON string but got `%s`", jsonObj.get("privilege").toString())); + } + if ((jsonObj.get("granted_on") != null && !jsonObj.get("granted_on").isJsonNull()) && !jsonObj.get("granted_on").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `granted_on` to be a primitive type in the JSON string but got `%s`", jsonObj.get("granted_on").toString())); + } + if ((jsonObj.get("name") != null && !jsonObj.get("name").isJsonNull()) && !jsonObj.get("name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("name").toString())); + } + if ((jsonObj.get("granted_to") != null && !jsonObj.get("granted_to").isJsonNull()) && !jsonObj.get("granted_to").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `granted_to` to be a primitive type in the JSON string but got `%s`", jsonObj.get("granted_to").toString())); + } + if ((jsonObj.get("grantee_name") != null && !jsonObj.get("grantee_name").isJsonNull()) && !jsonObj.get("grantee_name").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `grantee_name` to be a primitive type in the JSON string but got `%s`", jsonObj.get("grantee_name").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceRoleGrantTo.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceRoleGrantTo' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceRoleGrantTo.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceRoleGrantTo value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceRoleGrantTo read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceRoleGrantTo given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceRoleGrantTo + * @throws IOException if the JSON string is invalid with respect to ServiceRoleGrantTo + */ + public static ServiceRoleGrantTo fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceRoleGrantTo.class); + } + + /** + * Convert an instance of ServiceRoleGrantTo to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java new file mode 100644 index 00000000..c5ad70ec --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpec.java @@ -0,0 +1,242 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * Specifies service specification. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceSpec { + public static final String SERIALIZED_NAME_SPEC_TYPE = "spec_type"; + @SerializedName(SERIALIZED_NAME_SPEC_TYPE) + @javax.annotation.Nullable + protected String specType; + + public ServiceSpec() { + this.specType = this.getClass().getSimpleName(); + } + + public ServiceSpec specType(@javax.annotation.Nullable String specType) { + this.specType = specType; + return this; + } + + /** + * Type of the service specification, can be `from_file` or `from_inline`. + * @return specType + */ + @javax.annotation.Nullable + public String getSpecType() { + return specType; + } + + public void setSpecType(@javax.annotation.Nullable String specType) { + this.specType = specType; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpec serviceSpec = (ServiceSpec) o; + return Objects.equals(this.specType, serviceSpec.specType); + } + + @Override + public int hashCode() { + return Objects.hash(specType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpec {\n"); + sb.append(" specType: ").append(toIndentedString(specType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("spec_type")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceSpec + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceSpec.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceSpec is not found in the empty JSON string", ServiceSpec.openapiRequiredFields.toString())); + } + } + + String discriminatorValue = jsonElement.getAsJsonObject().get("spec_type").getAsString(); + switch (discriminatorValue) { + case "from_file": + ServiceSpecStageFile.validateJsonElement(jsonElement); + break; + case "from_inline": + ServiceSpecInlineText.validateJsonElement(jsonElement); + break; + default: + throw new IllegalArgumentException(String.format(Locale.ROOT, "The value of the `spec_type` field `%s` does not match any key defined in the discriminator's mapping.", discriminatorValue)); + } + } + + + /** + * Create an instance of ServiceSpec given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceSpec + * @throws IOException if the JSON string is invalid with respect to ServiceSpec + */ + public static ServiceSpec fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceSpec.class); + } + + /** + * Convert an instance of ServiceSpec to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceSpec.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceSpec' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceSpec value) throws IOException { + // Use the appropriate adapter based on the actual type + // Use getDelegateAdapter to skip this factory to avoid infinite recursion + if (value instanceof ServiceSpecInlineText) { + TypeAdapter adapter = gson.getDelegateAdapter(CustomTypeAdapterFactory.this, TypeToken.get(ServiceSpecInlineText.class)); + adapter.write(out, (ServiceSpecInlineText) value); + } else if (value instanceof ServiceSpecStageFile) { + TypeAdapter adapter = gson.getDelegateAdapter(CustomTypeAdapterFactory.this, TypeToken.get(ServiceSpecStageFile.class)); + adapter.write(out, (ServiceSpecStageFile) value); + } else { + // Fallback to base class + TypeAdapter adapter = gson.getDelegateAdapter(CustomTypeAdapterFactory.this, TypeToken.get(ServiceSpec.class)); + adapter.write(out, value); + } + } + + @Override + public ServiceSpec read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + if (jsonElement == null || !jsonElement.isJsonObject()) { + return null; + } + + // Read discriminator value to determine which subclass to deserialize into + JsonObject jsonObject = jsonElement.getAsJsonObject(); + JsonElement specTypeElement = jsonObject.get("spec_type"); + if (specTypeElement == null || specTypeElement.isJsonNull()) { + throw new JsonParseException("Missing discriminator field 'spec_type' in ServiceSpec JSON"); + } + + String specType = specTypeElement.getAsString(); + + // Deserialize into the appropriate subclass based on discriminator + // Use getDelegateAdapter to skip this factory to avoid infinite recursion + switch (specType) { + case "from_inline": + TypeAdapter inlineAdapter = gson.getDelegateAdapter(CustomTypeAdapterFactory.this, TypeToken.get(ServiceSpecInlineText.class)); + return inlineAdapter.fromJsonTree(jsonElement); + case "from_file": + TypeAdapter stageFileAdapter = gson.getDelegateAdapter(CustomTypeAdapterFactory.this, TypeToken.get(ServiceSpecStageFile.class)); + return stageFileAdapter.fromJsonTree(jsonElement); + default: + throw new JsonParseException("Unknown discriminator value '" + specType + "' for ServiceSpec"); + } + } + + }.nullSafe(); + } + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java new file mode 100644 index 00000000..b98c0769 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecInlineText.java @@ -0,0 +1,215 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceSpecInlineText + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceSpecInlineText extends ServiceSpec { + public static final String SERIALIZED_NAME_SPEC_TEXT = "spec_text"; + @SerializedName(SERIALIZED_NAME_SPEC_TEXT) + @javax.annotation.Nonnull + private String specText; + + public ServiceSpecInlineText() { + this.specType = this.getClass().getSimpleName(); + } + + public ServiceSpecInlineText specText(@javax.annotation.Nonnull String specText) { + this.specText = specText; + return this; + } + + /** + * Specifies service specification. You can use a pair of dollar signs ($$) to delimit the beginning and ending of the specification string. + * @return specText + */ + @javax.annotation.Nonnull + public String getSpecText() { + return specText; + } + + public void setSpecText(@javax.annotation.Nonnull String specText) { + this.specText = specText; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpecInlineText serviceSpecInlineText = (ServiceSpecInlineText) o; + return Objects.equals(this.specText, serviceSpecInlineText.specText) && + super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(specText, super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpecInlineText {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" specText: ").append(toIndentedString(specText)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("spec_type", "spec_text")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("spec_text")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceSpecInlineText + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceSpecInlineText.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceSpecInlineText is not found in the empty JSON string", ServiceSpecInlineText.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceSpecInlineText.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceSpecInlineText` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : ServiceSpecInlineText.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceSpecInlineText.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceSpecInlineText' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceSpecInlineText.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceSpecInlineText value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceSpecInlineText read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceSpecInlineText given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceSpecInlineText + * @throws IOException if the JSON string is invalid with respect to ServiceSpecInlineText + */ + public static ServiceSpecInlineText fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceSpecInlineText.class); + } + + /** + * Convert an instance of ServiceSpecInlineText to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java new file mode 100644 index 00000000..bc1cef3a --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/ServiceSpecStageFile.java @@ -0,0 +1,241 @@ +/* + * Snowflake Services API + * The Snowflake Services API is a REST API that you can use to access, update, and perform certain actions on Services resource in a Snowflake database. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * ServiceSpecStageFile + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:48.337179400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class ServiceSpecStageFile extends ServiceSpec { + public static final String SERIALIZED_NAME_STAGE = "stage"; + @SerializedName(SERIALIZED_NAME_STAGE) + @javax.annotation.Nonnull + private String stage; + + public static final String SERIALIZED_NAME_SPEC_FILE = "spec_file"; + @SerializedName(SERIALIZED_NAME_SPEC_FILE) + @javax.annotation.Nonnull + private String specFile; + + public ServiceSpecStageFile() { + this.specType = this.getClass().getSimpleName(); + } + + public ServiceSpecStageFile stage(@javax.annotation.Nonnull String stage) { + this.stage = stage; + return this; + } + + /** + * Specifies the Snowflake internal stage where the specification file is stored; for example, @tutorial_stage. + * @return stage + */ + @javax.annotation.Nonnull + public String getStage() { + return stage; + } + + public void setStage(@javax.annotation.Nonnull String stage) { + this.stage = stage; + } + + + public ServiceSpecStageFile specFile(@javax.annotation.Nonnull String specFile) { + this.specFile = specFile; + return this; + } + + /** + * Specifies the path to the service specification file on the stage; for example, 'some-dir/echo_spec.yaml'. + * @return specFile + */ + @javax.annotation.Nonnull + public String getSpecFile() { + return specFile; + } + + public void setSpecFile(@javax.annotation.Nonnull String specFile) { + this.specFile = specFile; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceSpecStageFile serviceSpecStageFile = (ServiceSpecStageFile) o; + return Objects.equals(this.stage, serviceSpecStageFile.stage) && + Objects.equals(this.specFile, serviceSpecStageFile.specFile) && + super.equals(o); + } + + @Override + public int hashCode() { + return Objects.hash(stage, specFile, super.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceSpecStageFile {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" stage: ").append(toIndentedString(stage)).append("\n"); + sb.append(" specFile: ").append(toIndentedString(specFile)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("spec_type", "stage", "spec_file")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(Arrays.asList("stage", "spec_file")); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to ServiceSpecStageFile + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!ServiceSpecStageFile.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in ServiceSpecStageFile is not found in the empty JSON string", ServiceSpecStageFile.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!ServiceSpecStageFile.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `ServiceSpecStageFile` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : ServiceSpecStageFile.openapiRequiredFields) { + if (jsonElement.getAsJsonObject().get(requiredField) == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString())); + } + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!ServiceSpecStageFile.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'ServiceSpecStageFile' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(ServiceSpecStageFile.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, ServiceSpecStageFile value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public ServiceSpecStageFile read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of ServiceSpecStageFile given an JSON string + * + * @param jsonString JSON string + * @return An instance of ServiceSpecStageFile + * @throws IOException if the JSON string is invalid with respect to ServiceSpecStageFile + */ + public static ServiceSpecStageFile fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, ServiceSpecStageFile.class); + } + + /** + * Convert an instance of ServiceSpecStageFile to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java new file mode 100644 index 00000000..c97964f8 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequest.java @@ -0,0 +1,407 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import eu.openanalytics.containerproxy.backend.spcs.client.model.SubmitStatementRequestParameters; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * SubmitStatementRequest + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SubmitStatementRequest { + public static final String SERIALIZED_NAME_STATEMENT = "statement"; + @SerializedName(SERIALIZED_NAME_STATEMENT) + @javax.annotation.Nullable + private String statement; + + public static final String SERIALIZED_NAME_TIMEOUT = "timeout"; + @SerializedName(SERIALIZED_NAME_TIMEOUT) + @javax.annotation.Nullable + private Long timeout; + + public static final String SERIALIZED_NAME_DATABASE = "database"; + @SerializedName(SERIALIZED_NAME_DATABASE) + @javax.annotation.Nullable + private String database; + + public static final String SERIALIZED_NAME_SCHEMA = "schema"; + @SerializedName(SERIALIZED_NAME_SCHEMA) + @javax.annotation.Nullable + private String schema; + + public static final String SERIALIZED_NAME_WAREHOUSE = "warehouse"; + @SerializedName(SERIALIZED_NAME_WAREHOUSE) + @javax.annotation.Nullable + private String warehouse; + + public static final String SERIALIZED_NAME_ROLE = "role"; + @SerializedName(SERIALIZED_NAME_ROLE) + @javax.annotation.Nullable + private String role; + + public static final String SERIALIZED_NAME_BINDINGS = "bindings"; + @SerializedName(SERIALIZED_NAME_BINDINGS) + @javax.annotation.Nullable + private Object bindings; + + public static final String SERIALIZED_NAME_PARAMETERS = "parameters"; + @SerializedName(SERIALIZED_NAME_PARAMETERS) + @javax.annotation.Nullable + private SubmitStatementRequestParameters parameters; + + public SubmitStatementRequest() { + } + + public SubmitStatementRequest statement(@javax.annotation.Nullable String statement) { + this.statement = statement; + return this; + } + + /** + * SQL statement or batch of SQL statements to execute. You can specify query, DML and DDL statements. The following statements are not supported: PUT, GET, USE, ALTER SESSION, BEGIN, COMMIT, ROLLBACK, statements that set session variables, and statements that create temporary tables and stages. + * @return statement + */ + @javax.annotation.Nullable + public String getStatement() { + return statement; + } + + public void setStatement(@javax.annotation.Nullable String statement) { + this.statement = statement; + } + + + public SubmitStatementRequest timeout(@javax.annotation.Nullable Long timeout) { + this.timeout = timeout; + return this; + } + + /** + * Timeout in seconds for statement execution. If the execution of a statement takes longer than the specified timeout, the execution is automatically canceled. To set the timeout to the maximum value (604800 seconds), set timeout to 0. + * minimum: 0 + * @return timeout + */ + @javax.annotation.Nullable + public Long getTimeout() { + return timeout; + } + + public void setTimeout(@javax.annotation.Nullable Long timeout) { + this.timeout = timeout; + } + + + public SubmitStatementRequest database(@javax.annotation.Nullable String database) { + this.database = database; + return this; + } + + /** + * Database in which the statement should be executed. The value in this field is case-sensitive. + * @return database + */ + @javax.annotation.Nullable + public String getDatabase() { + return database; + } + + public void setDatabase(@javax.annotation.Nullable String database) { + this.database = database; + } + + + public SubmitStatementRequest schema(@javax.annotation.Nullable String schema) { + this.schema = schema; + return this; + } + + /** + * Schema in which the statement should be executed. The value in this field is case-sensitive. + * @return schema + */ + @javax.annotation.Nullable + public String getSchema() { + return schema; + } + + public void setSchema(@javax.annotation.Nullable String schema) { + this.schema = schema; + } + + + public SubmitStatementRequest warehouse(@javax.annotation.Nullable String warehouse) { + this.warehouse = warehouse; + return this; + } + + /** + * Warehouse to use when executing the statement. The value in this field is case-sensitive. + * @return warehouse + */ + @javax.annotation.Nullable + public String getWarehouse() { + return warehouse; + } + + public void setWarehouse(@javax.annotation.Nullable String warehouse) { + this.warehouse = warehouse; + } + + + public SubmitStatementRequest role(@javax.annotation.Nullable String role) { + this.role = role; + return this; + } + + /** + * Role to use when executing the statement. The value in this field is case-sensitive. + * @return role + */ + @javax.annotation.Nullable + public String getRole() { + return role; + } + + public void setRole(@javax.annotation.Nullable String role) { + this.role = role; + } + + + public SubmitStatementRequest bindings(@javax.annotation.Nullable Object bindings) { + this.bindings = bindings; + return this; + } + + /** + * Values of bind variables in the SQL statement. When executing the statement, Snowflake replaces placeholders ('?' and ':name') in the statement with these specified values. + * @return bindings + */ + @javax.annotation.Nullable + public Object getBindings() { + return bindings; + } + + public void setBindings(@javax.annotation.Nullable Object bindings) { + this.bindings = bindings; + } + + + public SubmitStatementRequest parameters(@javax.annotation.Nullable SubmitStatementRequestParameters parameters) { + this.parameters = parameters; + return this; + } + + /** + * Get parameters + * @return parameters + */ + @javax.annotation.Nullable + public SubmitStatementRequestParameters getParameters() { + return parameters; + } + + public void setParameters(@javax.annotation.Nullable SubmitStatementRequestParameters parameters) { + this.parameters = parameters; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubmitStatementRequest submitStatementRequest = (SubmitStatementRequest) o; + return Objects.equals(this.statement, submitStatementRequest.statement) && + Objects.equals(this.timeout, submitStatementRequest.timeout) && + Objects.equals(this.database, submitStatementRequest.database) && + Objects.equals(this.schema, submitStatementRequest.schema) && + Objects.equals(this.warehouse, submitStatementRequest.warehouse) && + Objects.equals(this.role, submitStatementRequest.role) && + Objects.equals(this.bindings, submitStatementRequest.bindings) && + Objects.equals(this.parameters, submitStatementRequest.parameters); + } + + @Override + public int hashCode() { + return Objects.hash(statement, timeout, database, schema, warehouse, role, bindings, parameters); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SubmitStatementRequest {\n"); + sb.append(" statement: ").append(toIndentedString(statement)).append("\n"); + sb.append(" timeout: ").append(toIndentedString(timeout)).append("\n"); + sb.append(" database: ").append(toIndentedString(database)).append("\n"); + sb.append(" schema: ").append(toIndentedString(schema)).append("\n"); + sb.append(" warehouse: ").append(toIndentedString(warehouse)).append("\n"); + sb.append(" role: ").append(toIndentedString(role)).append("\n"); + sb.append(" bindings: ").append(toIndentedString(bindings)).append("\n"); + sb.append(" parameters: ").append(toIndentedString(parameters)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("statement", "timeout", "database", "schema", "warehouse", "role", "bindings", "parameters")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to SubmitStatementRequest + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!SubmitStatementRequest.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in SubmitStatementRequest is not found in the empty JSON string", SubmitStatementRequest.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!SubmitStatementRequest.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `SubmitStatementRequest` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("statement") != null && !jsonObj.get("statement").isJsonNull()) && !jsonObj.get("statement").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `statement` to be a primitive type in the JSON string but got `%s`", jsonObj.get("statement").toString())); + } + if ((jsonObj.get("database") != null && !jsonObj.get("database").isJsonNull()) && !jsonObj.get("database").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `database` to be a primitive type in the JSON string but got `%s`", jsonObj.get("database").toString())); + } + if ((jsonObj.get("schema") != null && !jsonObj.get("schema").isJsonNull()) && !jsonObj.get("schema").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `schema` to be a primitive type in the JSON string but got `%s`", jsonObj.get("schema").toString())); + } + if ((jsonObj.get("warehouse") != null && !jsonObj.get("warehouse").isJsonNull()) && !jsonObj.get("warehouse").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `warehouse` to be a primitive type in the JSON string but got `%s`", jsonObj.get("warehouse").toString())); + } + if ((jsonObj.get("role") != null && !jsonObj.get("role").isJsonNull()) && !jsonObj.get("role").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `role` to be a primitive type in the JSON string but got `%s`", jsonObj.get("role").toString())); + } + // validate the optional field `parameters` + if (jsonObj.get("parameters") != null && !jsonObj.get("parameters").isJsonNull()) { + SubmitStatementRequestParameters.validateJsonElement(jsonObj.get("parameters")); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!SubmitStatementRequest.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'SubmitStatementRequest' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(SubmitStatementRequest.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, SubmitStatementRequest value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public SubmitStatementRequest read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of SubmitStatementRequest given an JSON string + * + * @param jsonString JSON string + * @return An instance of SubmitStatementRequest + * @throws IOException if the JSON string is invalid with respect to SubmitStatementRequest + */ + public static SubmitStatementRequest fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, SubmitStatementRequest.class); + } + + /** + * Convert an instance of SubmitStatementRequest to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java new file mode 100644 index 00000000..50238dd2 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SubmitStatementRequestParameters.java @@ -0,0 +1,465 @@ +/* + * Snowflake SQL API + * The Snowflake SQL API is a REST API that you can use to access and update data in a Snowflake database. + * + * The version of the OpenAPI document: 2.0.0 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * Session parameters that should be set before executing the statement. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:47:56.670263400+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SubmitStatementRequestParameters { + public static final String SERIALIZED_NAME_TIMEZONE = "timezone"; + @SerializedName(SERIALIZED_NAME_TIMEZONE) + @javax.annotation.Nullable + private String timezone; + + public static final String SERIALIZED_NAME_QUERY_TAG = "query_tag"; + @SerializedName(SERIALIZED_NAME_QUERY_TAG) + @javax.annotation.Nullable + private String queryTag; + + public static final String SERIALIZED_NAME_BINARY_OUTPUT_FORMAT = "binary_output_format"; + @SerializedName(SERIALIZED_NAME_BINARY_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String binaryOutputFormat; + + public static final String SERIALIZED_NAME_DATE_OUTPUT_FORMAT = "date_output_format"; + @SerializedName(SERIALIZED_NAME_DATE_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String dateOutputFormat; + + public static final String SERIALIZED_NAME_TIME_OUTPUT_FORMAT = "time_output_format"; + @SerializedName(SERIALIZED_NAME_TIME_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timeOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_OUTPUT_FORMAT = "timestamp_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_LTZ_OUTPUT_FORMAT = "timestamp_ltz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_LTZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampLtzOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_NTZ_OUTPUT_FORMAT = "timestamp_ntz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_NTZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampNtzOutputFormat; + + public static final String SERIALIZED_NAME_TIMESTAMP_TZ_OUTPUT_FORMAT = "timestamp_tz_output_format"; + @SerializedName(SERIALIZED_NAME_TIMESTAMP_TZ_OUTPUT_FORMAT) + @javax.annotation.Nullable + private String timestampTzOutputFormat; + + public static final String SERIALIZED_NAME_MULTI_STATEMENT_COUNT = "multi_statement_count"; + @SerializedName(SERIALIZED_NAME_MULTI_STATEMENT_COUNT) + @javax.annotation.Nullable + private Integer multiStatementCount = 1; + + public SubmitStatementRequestParameters() { + } + + public SubmitStatementRequestParameters timezone(@javax.annotation.Nullable String timezone) { + this.timezone = timezone; + return this; + } + + /** + * Time zone to use when executing the statement. + * @return timezone + */ + @javax.annotation.Nullable + public String getTimezone() { + return timezone; + } + + public void setTimezone(@javax.annotation.Nullable String timezone) { + this.timezone = timezone; + } + + + public SubmitStatementRequestParameters queryTag(@javax.annotation.Nullable String queryTag) { + this.queryTag = queryTag; + return this; + } + + /** + * Query tag that you want to associate with the SQL statement. + * @return queryTag + */ + @javax.annotation.Nullable + public String getQueryTag() { + return queryTag; + } + + public void setQueryTag(@javax.annotation.Nullable String queryTag) { + this.queryTag = queryTag; + } + + + public SubmitStatementRequestParameters binaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + return this; + } + + /** + * Output format for binary values. + * @return binaryOutputFormat + */ + @javax.annotation.Nullable + public String getBinaryOutputFormat() { + return binaryOutputFormat; + } + + public void setBinaryOutputFormat(@javax.annotation.Nullable String binaryOutputFormat) { + this.binaryOutputFormat = binaryOutputFormat; + } + + + public SubmitStatementRequestParameters dateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + return this; + } + + /** + * Output format for DATE values. + * @return dateOutputFormat + */ + @javax.annotation.Nullable + public String getDateOutputFormat() { + return dateOutputFormat; + } + + public void setDateOutputFormat(@javax.annotation.Nullable String dateOutputFormat) { + this.dateOutputFormat = dateOutputFormat; + } + + + public SubmitStatementRequestParameters timeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + return this; + } + + /** + * Output format for TIME values. + * @return timeOutputFormat + */ + @javax.annotation.Nullable + public String getTimeOutputFormat() { + return timeOutputFormat; + } + + public void setTimeOutputFormat(@javax.annotation.Nullable String timeOutputFormat) { + this.timeOutputFormat = timeOutputFormat; + } + + + public SubmitStatementRequestParameters timestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP values. + * @return timestampOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampOutputFormat() { + return timestampOutputFormat; + } + + public void setTimestampOutputFormat(@javax.annotation.Nullable String timestampOutputFormat) { + this.timestampOutputFormat = timestampOutputFormat; + } + + + public SubmitStatementRequestParameters timestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_LTZ values. + * @return timestampLtzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampLtzOutputFormat() { + return timestampLtzOutputFormat; + } + + public void setTimestampLtzOutputFormat(@javax.annotation.Nullable String timestampLtzOutputFormat) { + this.timestampLtzOutputFormat = timestampLtzOutputFormat; + } + + + public SubmitStatementRequestParameters timestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_NTZ values. + * @return timestampNtzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampNtzOutputFormat() { + return timestampNtzOutputFormat; + } + + public void setTimestampNtzOutputFormat(@javax.annotation.Nullable String timestampNtzOutputFormat) { + this.timestampNtzOutputFormat = timestampNtzOutputFormat; + } + + + public SubmitStatementRequestParameters timestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + return this; + } + + /** + * Output format for TIMESTAMP_TZ values. + * @return timestampTzOutputFormat + */ + @javax.annotation.Nullable + public String getTimestampTzOutputFormat() { + return timestampTzOutputFormat; + } + + public void setTimestampTzOutputFormat(@javax.annotation.Nullable String timestampTzOutputFormat) { + this.timestampTzOutputFormat = timestampTzOutputFormat; + } + + + public SubmitStatementRequestParameters multiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + return this; + } + + /** + * Number of statements to execute when using multi-statement capability. 0 implies variable number of statements. Negative numbers are not allowed. + * @return multiStatementCount + */ + @javax.annotation.Nullable + public Integer getMultiStatementCount() { + return multiStatementCount; + } + + public void setMultiStatementCount(@javax.annotation.Nullable Integer multiStatementCount) { + this.multiStatementCount = multiStatementCount; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SubmitStatementRequestParameters submitStatementRequestParameters = (SubmitStatementRequestParameters) o; + return Objects.equals(this.timezone, submitStatementRequestParameters.timezone) && + Objects.equals(this.queryTag, submitStatementRequestParameters.queryTag) && + Objects.equals(this.binaryOutputFormat, submitStatementRequestParameters.binaryOutputFormat) && + Objects.equals(this.dateOutputFormat, submitStatementRequestParameters.dateOutputFormat) && + Objects.equals(this.timeOutputFormat, submitStatementRequestParameters.timeOutputFormat) && + Objects.equals(this.timestampOutputFormat, submitStatementRequestParameters.timestampOutputFormat) && + Objects.equals(this.timestampLtzOutputFormat, submitStatementRequestParameters.timestampLtzOutputFormat) && + Objects.equals(this.timestampNtzOutputFormat, submitStatementRequestParameters.timestampNtzOutputFormat) && + Objects.equals(this.timestampTzOutputFormat, submitStatementRequestParameters.timestampTzOutputFormat) && + Objects.equals(this.multiStatementCount, submitStatementRequestParameters.multiStatementCount); + } + + @Override + public int hashCode() { + return Objects.hash(timezone, queryTag, binaryOutputFormat, dateOutputFormat, timeOutputFormat, timestampOutputFormat, timestampLtzOutputFormat, timestampNtzOutputFormat, timestampTzOutputFormat, multiStatementCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SubmitStatementRequestParameters {\n"); + sb.append(" timezone: ").append(toIndentedString(timezone)).append("\n"); + sb.append(" queryTag: ").append(toIndentedString(queryTag)).append("\n"); + sb.append(" binaryOutputFormat: ").append(toIndentedString(binaryOutputFormat)).append("\n"); + sb.append(" dateOutputFormat: ").append(toIndentedString(dateOutputFormat)).append("\n"); + sb.append(" timeOutputFormat: ").append(toIndentedString(timeOutputFormat)).append("\n"); + sb.append(" timestampOutputFormat: ").append(toIndentedString(timestampOutputFormat)).append("\n"); + sb.append(" timestampLtzOutputFormat: ").append(toIndentedString(timestampLtzOutputFormat)).append("\n"); + sb.append(" timestampNtzOutputFormat: ").append(toIndentedString(timestampNtzOutputFormat)).append("\n"); + sb.append(" timestampTzOutputFormat: ").append(toIndentedString(timestampTzOutputFormat)).append("\n"); + sb.append(" multiStatementCount: ").append(toIndentedString(multiStatementCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("timezone", "query_tag", "binary_output_format", "date_output_format", "time_output_format", "timestamp_output_format", "timestamp_ltz_output_format", "timestamp_ntz_output_format", "timestamp_tz_output_format", "multi_statement_count")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to SubmitStatementRequestParameters + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!SubmitStatementRequestParameters.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in SubmitStatementRequestParameters is not found in the empty JSON string", SubmitStatementRequestParameters.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!SubmitStatementRequestParameters.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `SubmitStatementRequestParameters` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("timezone") != null && !jsonObj.get("timezone").isJsonNull()) && !jsonObj.get("timezone").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timezone` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timezone").toString())); + } + if ((jsonObj.get("query_tag") != null && !jsonObj.get("query_tag").isJsonNull()) && !jsonObj.get("query_tag").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `query_tag` to be a primitive type in the JSON string but got `%s`", jsonObj.get("query_tag").toString())); + } + if ((jsonObj.get("binary_output_format") != null && !jsonObj.get("binary_output_format").isJsonNull()) && !jsonObj.get("binary_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `binary_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("binary_output_format").toString())); + } + if ((jsonObj.get("date_output_format") != null && !jsonObj.get("date_output_format").isJsonNull()) && !jsonObj.get("date_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `date_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("date_output_format").toString())); + } + if ((jsonObj.get("time_output_format") != null && !jsonObj.get("time_output_format").isJsonNull()) && !jsonObj.get("time_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `time_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("time_output_format").toString())); + } + if ((jsonObj.get("timestamp_output_format") != null && !jsonObj.get("timestamp_output_format").isJsonNull()) && !jsonObj.get("timestamp_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_output_format").toString())); + } + if ((jsonObj.get("timestamp_ltz_output_format") != null && !jsonObj.get("timestamp_ltz_output_format").isJsonNull()) && !jsonObj.get("timestamp_ltz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_ltz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_ltz_output_format").toString())); + } + if ((jsonObj.get("timestamp_ntz_output_format") != null && !jsonObj.get("timestamp_ntz_output_format").isJsonNull()) && !jsonObj.get("timestamp_ntz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_ntz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_ntz_output_format").toString())); + } + if ((jsonObj.get("timestamp_tz_output_format") != null && !jsonObj.get("timestamp_tz_output_format").isJsonNull()) && !jsonObj.get("timestamp_tz_output_format").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `timestamp_tz_output_format` to be a primitive type in the JSON string but got `%s`", jsonObj.get("timestamp_tz_output_format").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!SubmitStatementRequestParameters.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'SubmitStatementRequestParameters' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(SubmitStatementRequestParameters.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, SubmitStatementRequestParameters value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public SubmitStatementRequestParameters read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of SubmitStatementRequestParameters given an JSON string + * + * @param jsonString JSON string + * @return An instance of SubmitStatementRequestParameters + * @throws IOException if the JSON string is invalid with respect to SubmitStatementRequestParameters + */ + public static SubmitStatementRequestParameters fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, SubmitStatementRequestParameters.class); + } + + /** + * Convert an instance of SubmitStatementRequestParameters to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java new file mode 100644 index 00000000..9cf81a4e --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessAcceptedResponse.java @@ -0,0 +1,266 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * Schema for a request in progress response returned by the server. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SuccessAcceptedResponse { + public static final String SERIALIZED_NAME_CODE = "code"; + @SerializedName(SERIALIZED_NAME_CODE) + @javax.annotation.Nullable + private String code; + + public static final String SERIALIZED_NAME_MESSAGE = "message"; + @SerializedName(SERIALIZED_NAME_MESSAGE) + @javax.annotation.Nullable + private String message; + + public static final String SERIALIZED_NAME_RESULT_HANDLER = "resultHandler"; + @SerializedName(SERIALIZED_NAME_RESULT_HANDLER) + @javax.annotation.Nullable + private String resultHandler; + + public SuccessAcceptedResponse() { + } + + public SuccessAcceptedResponse code(@javax.annotation.Nullable String code) { + this.code = code; + return this; + } + + /** + * Message code returned by the server. + * @return code + */ + @javax.annotation.Nullable + public String getCode() { + return code; + } + + public void setCode(@javax.annotation.Nullable String code) { + this.code = code; + } + + + public SuccessAcceptedResponse message(@javax.annotation.Nullable String message) { + this.message = message; + return this; + } + + /** + * Message returned by the server + * @return message + */ + @javax.annotation.Nullable + public String getMessage() { + return message; + } + + public void setMessage(@javax.annotation.Nullable String message) { + this.message = message; + } + + + public SuccessAcceptedResponse resultHandler(@javax.annotation.Nullable String resultHandler) { + this.resultHandler = resultHandler; + return this; + } + + /** + * Opaque result ID used for checking for request completion through one or more subsequent completion check operations. + * @return resultHandler + */ + @javax.annotation.Nullable + public String getResultHandler() { + return resultHandler; + } + + public void setResultHandler(@javax.annotation.Nullable String resultHandler) { + this.resultHandler = resultHandler; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SuccessAcceptedResponse successAcceptedResponse = (SuccessAcceptedResponse) o; + return Objects.equals(this.code, successAcceptedResponse.code) && + Objects.equals(this.message, successAcceptedResponse.message) && + Objects.equals(this.resultHandler, successAcceptedResponse.resultHandler); + } + + @Override + public int hashCode() { + return Objects.hash(code, message, resultHandler); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SuccessAcceptedResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" resultHandler: ").append(toIndentedString(resultHandler)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("code", "message", "resultHandler")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to SuccessAcceptedResponse + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!SuccessAcceptedResponse.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in SuccessAcceptedResponse is not found in the empty JSON string", SuccessAcceptedResponse.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!SuccessAcceptedResponse.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `SuccessAcceptedResponse` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("code") != null && !jsonObj.get("code").isJsonNull()) && !jsonObj.get("code").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `code` to be a primitive type in the JSON string but got `%s`", jsonObj.get("code").toString())); + } + if ((jsonObj.get("message") != null && !jsonObj.get("message").isJsonNull()) && !jsonObj.get("message").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `message` to be a primitive type in the JSON string but got `%s`", jsonObj.get("message").toString())); + } + if ((jsonObj.get("resultHandler") != null && !jsonObj.get("resultHandler").isJsonNull()) && !jsonObj.get("resultHandler").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `resultHandler` to be a primitive type in the JSON string but got `%s`", jsonObj.get("resultHandler").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!SuccessAcceptedResponse.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'SuccessAcceptedResponse' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(SuccessAcceptedResponse.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, SuccessAcceptedResponse value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public SuccessAcceptedResponse read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of SuccessAcceptedResponse given an JSON string + * + * @param jsonString JSON string + * @return An instance of SuccessAcceptedResponse + * @throws IOException if the JSON string is invalid with respect to SuccessAcceptedResponse + */ + public static SuccessAcceptedResponse fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, SuccessAcceptedResponse.class); + } + + /** + * Convert an instance of SuccessAcceptedResponse to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java new file mode 100644 index 00000000..3cc5c696 --- /dev/null +++ b/src/main/java/eu/openanalytics/containerproxy/backend/spcs/client/model/SuccessResponse.java @@ -0,0 +1,208 @@ +/* + * Snowflake Warehouse API + * The Snowflake Warehouse API is a REST API that you can use to access, customize and manage virtual warehouse in a Snowflake account. + * + * The version of the OpenAPI document: 0.0.1 + * Contact: support@snowflake.com + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +package eu.openanalytics.containerproxy.backend.spcs.client.model; + +import java.util.Objects; +import java.util.Locale; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Locale; + +import eu.openanalytics.containerproxy.backend.spcs.client.JSON; + +/** + * Schema for all the success responses returned by the server. + */ +@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2025-12-06T17:48:43.068946900+08:00[Australia/Perth]", comments = "Generator version: 7.17.0") +public class SuccessResponse { + public static final String SERIALIZED_NAME_STATUS = "status"; + @SerializedName(SERIALIZED_NAME_STATUS) + @javax.annotation.Nullable + private String status; + + public SuccessResponse() { + } + + public SuccessResponse status(@javax.annotation.Nullable String status) { + this.status = status; + return this; + } + + /** + * Message returned by the server. + * @return status + */ + @javax.annotation.Nullable + public String getStatus() { + return status; + } + + public void setStatus(@javax.annotation.Nullable String status) { + this.status = status; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SuccessResponse successResponse = (SuccessResponse) o; + return Objects.equals(this.status, successResponse.status); + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class SuccessResponse {\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(Arrays.asList("status")); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(0); + } + + /** + * Validates the JSON Element and throws an exception if issues found + * + * @param jsonElement JSON Element + * @throws IOException if the JSON Element is invalid with respect to SuccessResponse + */ + public static void validateJsonElement(JsonElement jsonElement) throws IOException { + if (jsonElement == null) { + if (!SuccessResponse.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null + throw new IllegalArgumentException(String.format(Locale.ROOT, "The required field(s) %s in SuccessResponse is not found in the empty JSON string", SuccessResponse.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonElement.getAsJsonObject().entrySet(); + // check to see if the JSON string contains additional fields + for (Map.Entry entry : entries) { + if (!SuccessResponse.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "The field `%s` in the JSON string is not defined in the `SuccessResponse` properties. JSON: %s", entry.getKey(), jsonElement.toString())); + } + } + JsonObject jsonObj = jsonElement.getAsJsonObject(); + if ((jsonObj.get("status") != null && !jsonObj.get("status").isJsonNull()) && !jsonObj.get("status").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format(Locale.ROOT, "Expected the field `status` to be a primitive type in the JSON string but got `%s`", jsonObj.get("status").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!SuccessResponse.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'SuccessResponse' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(SuccessResponse.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, SuccessResponse value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public SuccessResponse read(JsonReader in) throws IOException { + JsonElement jsonElement = elementAdapter.read(in); + validateJsonElement(jsonElement); + return thisAdapter.fromJsonTree(jsonElement); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of SuccessResponse given an JSON string + * + * @param jsonString JSON string + * @return An instance of SuccessResponse + * @throws IOException if the JSON string is invalid with respect to SuccessResponse + */ + public static SuccessResponse fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, SuccessResponse.class); + } + + /** + * Convert an instance of SuccessResponse to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} + + diff --git a/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java b/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java new file mode 100644 index 00000000..85ca2eb6 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/auth/SpcsAuthenticationTest.java @@ -0,0 +1,170 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.auth; + +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +public class SpcsAuthenticationTest { + + private static final String SNOWFLAKE_SERVICE_NAME_ENV = "SNOWFLAKE_SERVICE_NAME"; + private String originalServiceName; + + @BeforeEach + public void setUp() { + // Save original value and set SNOWFLAKE_SERVICE_NAME for SPCS authentication + // Spring Environment can read from system properties or environment variables + originalServiceName = System.getProperty(SNOWFLAKE_SERVICE_NAME_ENV); + if (originalServiceName == null) { + originalServiceName = System.getenv(SNOWFLAKE_SERVICE_NAME_ENV); + } + System.setProperty(SNOWFLAKE_SERVICE_NAME_ENV, "TEST_SERVICE"); + } + + @AfterEach + public void tearDown() { + // Restore original value + if (originalServiceName != null) { + System.setProperty(SNOWFLAKE_SERVICE_NAME_ENV, originalServiceName); + } else { + System.clearProperty(SNOWFLAKE_SERVICE_NAME_ENV); + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: TEST_USER_123" + // should return 200 + @Test + public void authenticateUserWithHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + String testUsername = "TEST_USER_123"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", testUsername) + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should authenticate successfully and return 200 (or appropriate success code) + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: TEST_USER_123" -H "Sf-Context-Current-User-Token: TEST_TOKEN_123" + // should return 200 + @Test + public void authenticateUserWithHeaderAndToken() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + String testUsername = "TEST_USER_456"; + String testToken = "TEST_TOKEN_123"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", testUsername) + .header("Sf-Context-Current-User-Token", testToken) + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should authenticate successfully with both headers + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } + + // curl -v http://localhost:7583/api/proxy + // should return 401 + @Test + public void authenticationFailsWithoutHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + // No Sf-Context-Current-User header + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should fail authentication - filter returns 401 UNAUTHORIZED + Assertions.assertEquals(401, response.code()); + String responseBody = response.body() != null ? response.body().string() : ""; + Assertions.assertTrue(responseBody.contains("SPCS authentication failed")); + } + } + } + + // curl -v http://localhost:7583/api/proxy -H "Sf-Context-Current-User: " + // should return 401 + @Test + public void authenticationFailsWithEmptyHeader() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs-auth.yml")) { + String baseUrl = "http://localhost:7583"; + + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy") + .header("Sf-Context-Current-User", "") // Empty header + .build(); + + try (Response response = client.newCall(request).execute()) { + // Should fail authentication - empty header is treated as missing + Assertions.assertEquals(401, response.code()); + String responseBody = response.body() != null ? response.body().string() : ""; + Assertions.assertTrue(responseBody.contains("SPCS authentication failed")); + } + } + } +} + diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java index b1f032f2..ca4be836 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java @@ -123,6 +123,10 @@ public boolean checkDockerIsClean() { List pods2 = client.pods().inNamespace(overriddenNamespace).list().getItems(); return new Retrying.Result(pods1.isEmpty() && pods2.isEmpty()); } + case "ecs", "spcs" -> { + // Cloud services don't need local cleanup check + return Retrying.SUCCESS; + } } return Retrying.SUCCESS; } catch (DockerException | InterruptedException | DockerCertificateException e) { diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java new file mode 100644 index 00000000..c256a3d9 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSpcs.java @@ -0,0 +1,299 @@ +/* + * ContainerProxy + * + * Copyright (C) 2016-2025 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.proxy; + +import com.google.common.base.Throwables; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiClient; +import eu.openanalytics.containerproxy.backend.spcs.client.ApiException; +import eu.openanalytics.containerproxy.backend.spcs.client.Configuration; +import eu.openanalytics.containerproxy.backend.spcs.client.auth.HttpBearerAuth; +import eu.openanalytics.containerproxy.backend.spcs.client.api.ServiceApi; +import eu.openanalytics.containerproxy.backend.spcs.client.model.Service; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceContainer; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpec; +import eu.openanalytics.containerproxy.backend.spcs.client.model.ServiceSpecInlineText; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerNameKey; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import eu.openanalytics.containerproxy.test.helpers.TestHelperException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; + +public class TestIntegrationOnSpcs { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + private static ServiceApi serviceApi; + + private ServiceApi getServiceApi() { + if (serviceApi == null) { + String accountName = System.getenv("ITEST_SPCS_ACCOUNT_NAME"); + if (accountName == null || accountName.isEmpty()) { + throw new IllegalStateException("ITEST_SPCS_ACCOUNT_NAME environment variable not set"); + } + // Construct account URL from account name + String accountUrl = String.format("https://%s.snowflakecomputing.com", accountName); + + // For tests, use PAT (Programmatic Access Token) authentication + String authToken = System.getenv("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN"); + if (authToken == null || authToken.isEmpty()) { + throw new IllegalStateException("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN environment variable must be set"); + } + + ApiClient apiClient = Configuration.getDefaultApiClient(); + apiClient.setBasePath(accountUrl); + + HttpBearerAuth keyPairAuth = (HttpBearerAuth) apiClient.getAuthentication("KeyPair"); + keyPairAuth.setBearerToken(authToken); + + serviceApi = new ServiceApi(apiClient); + } + return serviceApi; + } + + @Test + public void launchProxy() { + Assumptions.assumeTrue(checkSnowflakeCredentials(), "Skipping SPCS tests"); + try (ContainerSetup containerSetup = new ContainerSetup("spcs")) { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-spcs.yml", Map.of(), true)) { + inst.enableCleanup(); + // launch a proxy on SPCS + String id = inst.client.startProxy("01_hello"); + Proxy proxy = inst.proxyService.getProxy(id); + inst.client.testProxyReachable(id); + + Service service = getService(proxy); + + // Verify service properties + Assertions.assertNotNull(service.getDnsName()); + Assertions.assertTrue(service.getDnsName().contains(".svc.spcs.internal")); + // Compare compute pool case-insensitively as Snowflake may return it in different case + String expectedComputePool = System.getenv("ITEST_SPCS_COMPUTE_POOL"); + String actualComputePool = service.getComputePool(); + Assertions.assertNotNull(actualComputePool, "Compute pool should not be null"); + Assertions.assertTrue(actualComputePool.equalsIgnoreCase(expectedComputePool), + () -> String.format("Compute pool mismatch: expected '%s' (case-insensitive), got '%s'", expectedComputePool, actualComputePool)); + Assertions.assertNotNull(service.getStatus()); + + // Verify service containers are running + List containers = getServiceContainers(proxy); + Assertions.assertFalse(containers.isEmpty()); + + ServiceContainer container = containers.get(0); + Assertions.assertNotNull(container.getStatus()); + Assertions.assertTrue( + container.getStatus().equals("RUNNING") || + container.getStatus().equals("UP") || + container.getStatus().equals("READY") + ); + + // Verify service spec contains expected configuration + Assertions.assertNotNull(service.getSpec()); + ServiceSpec spec = service.getSpec(); + + // Check spec_type to determine the actual type (API may return base ServiceSpec) + String specType = spec.getSpecType(); + Assertions.assertNotNull(specType, "Service spec type should not be null"); + + // The spec should be of type "from_inline" (ServiceSpecInlineText) + // Verify spec type matches expected value (accept both "from_inline" and class name) + Assertions.assertTrue("from_inline".equals(specType) || "ServiceSpecInlineText".equals(specType), + () -> String.format("Service spec type should be 'from_inline' or 'ServiceSpecInlineText', but got: %s", specType)); + + // If API properly deserialized as ServiceSpecInlineText, validate spec text content + if (spec instanceof ServiceSpecInlineText) { + ServiceSpecInlineText inlineSpec = (ServiceSpecInlineText) spec; + String specText = inlineSpec.getSpecText(); + Assertions.assertNotNull(specText, "Service spec text should not be null"); + Assertions.assertTrue(specText.contains("openanalytics/shinyproxy-integration-test-app"), + () -> String.format("Spec text should contain image name, but got: %s", specText.substring(0, Math.min(200, specText.length())))); + Assertions.assertTrue(specText.contains("SHINYPROXY_USERNAME"), + "Spec text should contain SHINYPROXY_USERNAME environment variable"); + Assertions.assertTrue(specText.contains("demo"), + "Spec text should contain demo user"); + } else { + // API returned base ServiceSpec (deserialization issue), but spec type is correct + // This is acceptable - the spec type is validated above + logger.debug("Service spec is base ServiceSpec type (not ServiceSpecInlineText), but spec_type is correct: {}", specType); + } + + inst.client.stopProxy(id); + + // Verify service is deleted or stopped + // Note: Service deletion may be asynchronous + containers = getServiceContainers(proxy); + // After stopping, containers should be stopped/suspended or service should be deleted + boolean allStopped = containers.isEmpty() || containers.stream().allMatch(c -> + c.getStatus() != null && ( + c.getStatus().equals("STOPPED") || + c.getStatus().equals("SUSPENDED") || + c.getStatus().equals("DELETED") + ) + ); + Assertions.assertTrue(allStopped, "Service containers should be stopped after proxy stop"); + } + } + } + + @Test + public void testInvalidConfig1() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-1.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.account-identifier not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig2() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-2.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: one of the following must be set: proxy.spcs.private-rsa-key-path or proxy.spcs.programmatic-access-token", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig3() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-3.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.database not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig4() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-4.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.schema not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig5() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-5.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertEquals("Error in configuration of SPCS backend: proxy.spcs.compute-pool not set", rootCause.getMessage()); + } + + @Test + public void testInvalidConfig6() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-6.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has no 'memory-request' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("required for running on Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig7() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-7.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has no 'cpu-request' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("required for running on Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig8() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-8.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'memory-limit' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig9() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-9.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'cpu-limit' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + @Test + public void testInvalidConfig10() { + TestHelperException ex = Assertions.assertThrows(TestHelperException.class, () -> new ShinyProxyInstance("application-test-spcs-invalid-10.yml")); + Throwable rootCause = Throwables.getRootCause(ex); + Assertions.assertInstanceOf(IllegalStateException.class, rootCause); + Assertions.assertTrue(rootCause.getMessage().contains("has 'privileged: true' configured"), rootCause.getMessage()); + Assertions.assertTrue(rootCause.getMessage().contains("not supported by Snowflake SPCS"), rootCause.getMessage()); + } + + private Service getService(Proxy proxy) { + String fullServiceName = proxy.getContainers().getFirst().getRuntimeValue(BackendContainerNameKey.inst); + String[] parts = fullServiceName.split("\\."); + Assertions.assertEquals(3, parts.length, "Service name should be in format database.schema.service"); + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + + try { + return getServiceApi().fetchService(serviceDb, serviceSchema, serviceName); + } catch (ApiException e) { + throw new TestHelperException("Error fetching service: " + fullServiceName, e); + } + } + + private List getServiceContainers(Proxy proxy) { + String fullServiceName = proxy.getContainers().getFirst().getRuntimeValue(BackendContainerNameKey.inst); + String[] parts = fullServiceName.split("\\."); + Assertions.assertEquals(3, parts.length, "Service name should be in format database.schema.service"); + String serviceDb = parts[0]; + String serviceSchema = parts[1]; + String serviceName = parts[2]; + + try { + return getServiceApi().listServiceContainers(serviceDb, serviceSchema, serviceName); + } catch (ApiException e) { + // Service might be deleted, return empty list + if (e.getCode() == 404) { + return List.of(); + } + throw new TestHelperException("Error listing service containers: " + fullServiceName, e); + } + } + + private boolean requireEnvVar(String name) { + if (System.getenv(name) == null) { + logger.info("Env var {} missing, skipping SPCS Tests", name); + return false; + } + return true; + } + + private boolean checkSnowflakeCredentials() { + return requireEnvVar("ITEST_SPCS_ACCOUNT_NAME") + && requireEnvVar("ITEST_SPCS_USERNAME") + && requireEnvVar("ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN") + && requireEnvVar("ITEST_SPCS_DATABASE") + && requireEnvVar("ITEST_SPCS_SCHEMA") + && requireEnvVar("ITEST_SPCS_COMPUTE_POOL"); + } + +} + diff --git a/src/test/resources/application-test-spcs-auth.yml b/src/test/resources/application-test-spcs-auth.yml new file mode 100644 index 00000000..351d67ed --- /dev/null +++ b/src/test/resources/application-test-spcs-auth.yml @@ -0,0 +1,24 @@ +spring: + session: + store-type: none + data: + redis: + repositories: + enabled: false +proxy: + authentication: spcs + heartbeat-timeout: -1 + default-stop-proxy-on-logout: false + container-backend: spcs + spcs: + account-identifier: TEST_ACCOUNT + username: TEST_USER + programmatic-access-token: TEST_TOKEN + database: TEST_DB + schema: TEST_SCHEMA + compute-pool: TEST_POOL + specs: + - id: test_spec + container-specs: + - image: "test/image:latest" + diff --git a/src/test/resources/application-test-spcs.yml b/src/test/resources/application-test-spcs.yml new file mode 100644 index 00000000..c91bc8c1 --- /dev/null +++ b/src/test/resources/application-test-spcs.yml @@ -0,0 +1,38 @@ +spring: + session: + store-type: none + data: + redis: + repositories: + enabled: false +proxy: + authentication: simple + heartbeat-timeout: -1 + default-stop-proxy-on-logout: false + container-backend: spcs + spcs: + account-identifier: ${ITEST_SPCS_ACCOUNT_NAME} + username: ${ITEST_SPCS_USERNAME} + programmatic-access-token: ${ITEST_SPCS_PROGRAMMATIC_ACCESS_TOKEN} + database: ${ITEST_SPCS_DATABASE} + schema: ${ITEST_SPCS_SCHEMA} + compute-pool: ${ITEST_SPCS_COMPUTE_POOL} + users: + - name: demo + password: demo + - name: demo2 + password: demo2 + specs: + - id: 01_hello + container-specs: + - image: "/MYDB/images/shinyproxyimages/shinyproxy-integration-test-app:latest" + cmd: [ "R", "-e", "shinyproxy::run_01_hello()" ] + cpu-request: 1024 + memory-request: 2048 + port-mapping: + - name: default + port: 3838 + labels: + valid-label: myvalue + invalid-label: "$@$#$@" + invalid-label2: "value-is-too-looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"