-
Notifications
You must be signed in to change notification settings - Fork 8
MUT-1123 : SDK Support for CDF Service metrics_marvels/limits #421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
arnav-cognite
wants to merge
8
commits into
main
Choose a base branch
from
arnav/java-sdk-limits
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
06a8915
java sdk for limits-svc
94ec8a3
gemini suggestion
872a091
gemini suggestions applied v2
5e71112
gemini suggestion v3
ee27cc5
fixes
27f0b98
test improvements
217cfb9
adhering to common util standards
711e99d
fix
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,261 @@ | ||
| /* | ||
| * Copyright (c) 2020 Cognite AS | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package com.cognite.client; | ||
|
|
||
| import com.cognite.client.dto.LimitValue; | ||
| import com.cognite.client.servicesV1.ConnectorConstants; | ||
| import com.cognite.client.servicesV1.ResponseBinary; | ||
| import com.cognite.client.servicesV1.parser.LimitValueParser; | ||
| import com.cognite.client.servicesV1.util.JsonUtil; | ||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.google.auto.value.AutoValue; | ||
| import com.google.common.base.Preconditions; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.net.URI; | ||
| import java.util.ArrayList; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * This class represents the Cognite Limit Values API endpoint. | ||
| * | ||
| * It provides methods for reading {@link LimitValue} objects. | ||
| * | ||
| * Note: This API is currently in alpha and requires the cdf-version header. | ||
| */ | ||
| @AutoValue | ||
| public abstract class LimitValues extends ApiBase { | ||
|
|
||
| private static final String CDF_VERSION_HEADER = "cdf-version"; | ||
| private static final String CDF_VERSION_VALUE = "20230101-alpha"; | ||
| private static final ObjectMapper objectMapper = JsonUtil.getObjectMapperInstance(); | ||
|
|
||
| private static Builder builder() { | ||
| return new AutoValue_LimitValues.Builder(); | ||
| } | ||
|
|
||
| protected static final Logger LOG = LoggerFactory.getLogger(LimitValues.class); | ||
|
|
||
| /** | ||
| * Constructs a new {@link LimitValues} object using the provided client configuration. | ||
| * | ||
| * This method is intended for internal use--SDK clients should always use {@link CogniteClient} | ||
| * as the entry point to this class. | ||
| * | ||
| * @param client The {@link CogniteClient} to use for configuration settings. | ||
| * @return the limit values api object. | ||
| */ | ||
| public static LimitValues of(CogniteClient client) { | ||
| return LimitValues.builder() | ||
| .setClient(client) | ||
| .build(); | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves a specific limit value by its ID. | ||
| * | ||
| * <h2>Example:</h2> | ||
| * <pre> | ||
| * {@code | ||
| * LimitValue limitValue = client.limitValues().retrieve("my-limit-id"); | ||
| * } | ||
| * </pre> | ||
| * | ||
| * @param limitId The ID of the limit value to retrieve. | ||
| * @return The retrieved {@link LimitValue}. | ||
| * @throws Exception if the retrieval fails. | ||
| */ | ||
| public LimitValue retrieve(String limitId) throws Exception { | ||
arnav-cognite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Preconditions.checkArgument(limitId != null && !limitId.isBlank(), | ||
| "limitId cannot be null or blank."); | ||
|
|
||
| String loggingPrefix = "retrieve() - "; | ||
| LOG.debug(loggingPrefix + "Retrieving limit value with id: {}", limitId); | ||
|
|
||
| URI requestUri = buildUri("limits/values/" + limitId); | ||
|
|
||
| ResponseBinary response = getClient().experimental().cdfHttpRequest(requestUri) | ||
| .withHeader(CDF_VERSION_HEADER, CDF_VERSION_VALUE) | ||
| .get(); | ||
|
|
||
| if (!response.getResponse().isSuccessful()) { | ||
| throw new Exception("Failed to retrieve limit value. Response code: " | ||
| + response.getResponse().code() | ||
| + ", message: " + response.getResponse().message()); | ||
| } | ||
|
|
||
| String responseBody = response.getResponseBodyBytes().toStringUtf8(); | ||
| return parseLimitValue(responseBody); | ||
| } | ||
|
|
||
| /** | ||
| * Returns all {@link LimitValue} objects using pagination. | ||
| * | ||
| * <h2>Example:</h2> | ||
| * <pre> | ||
| * {@code | ||
| * List<LimitValue> allLimitValues = new ArrayList<>(); | ||
| * client.limitValues() | ||
| * .list() | ||
| * .forEachRemaining(allLimitValues::addAll); | ||
| * } | ||
| * </pre> | ||
| * | ||
| * @return An {@link Iterator} to page through the results. | ||
| */ | ||
| public Iterator<List<LimitValue>> list() throws Exception { | ||
| return list(Request.create()); | ||
| } | ||
|
|
||
| /** | ||
| * Returns {@link LimitValue} objects that match the filters set in the {@link Request}. | ||
| * | ||
| * The results are paged through / iterated over via an {@link Iterator}--the entire results set is not buffered in | ||
| * memory, but streamed in "pages" from the Cognite API. | ||
| * | ||
| * <h2>Example:</h2> | ||
| * <pre> | ||
| * {@code | ||
| * List<LimitValue> limitValues = new ArrayList<>(); | ||
| * client.limitValues() | ||
| * .list(Request.create() | ||
| * .withFilterParameter("prefix", Map.of( | ||
| * "property", List.of("limitId"), | ||
| * "value", "atlas."))) | ||
| * .forEachRemaining(limitValues::addAll); | ||
| * } | ||
| * </pre> | ||
| * | ||
| * @param requestParameters The filters to use for retrieving limit values. | ||
| * @return An {@link Iterator} to page through the results. | ||
| */ | ||
| public Iterator<List<LimitValue>> list(Request requestParameters) { | ||
| return new LimitValuesIterator(requestParameters); | ||
| } | ||
|
|
||
| /** | ||
| * Builds the URI for the limit values API endpoint. | ||
| * | ||
| * @param pathSegment The path segment to append (e.g., "limits/values/list") | ||
| * @return The complete URI | ||
| */ | ||
| private URI buildUri(String pathSegment) { | ||
| String baseUrl = getClient().getBaseUrl(); | ||
| String project = getClient().getProject(); | ||
| return URI.create(String.format("%s/api/v1/projects/%s/%s", | ||
| baseUrl, project, pathSegment)); | ||
| } | ||
|
|
||
| /** | ||
| * Parses a JSON string to a LimitValue object. | ||
| */ | ||
| private LimitValue parseLimitValue(String json) { | ||
| try { | ||
| return LimitValueParser.parseLimitValue(json); | ||
| } catch (Exception e) { | ||
| throw new RuntimeException("Failed to parse LimitValue from JSON: " + e.getMessage(), e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Iterator implementation for paginated limit values listing. | ||
| */ | ||
| private class LimitValuesIterator implements Iterator<List<LimitValue>> { | ||
| private final Request requestParameters; | ||
| private String cursor = null; | ||
| private boolean hasMore = true; | ||
|
|
||
| public LimitValuesIterator(Request requestParameters) { | ||
| this.requestParameters = requestParameters; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean hasNext() { | ||
| return hasMore; | ||
| } | ||
|
|
||
| @Override | ||
| public List<LimitValue> next() { | ||
| try { | ||
| return fetchNextBatch(); | ||
| } catch (Exception e) { | ||
| throw new RuntimeException("Failed to fetch next batch of limit values", e); | ||
| } | ||
| } | ||
|
|
||
| private List<LimitValue> fetchNextBatch() throws Exception { | ||
arnav-cognite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| URI requestUri = buildUri("limits/values/list"); | ||
|
|
||
| // Build request body with cursor if available | ||
| Map<String, Object> requestBody = new java.util.HashMap<>(requestParameters.getRequestParameters()); | ||
|
|
||
| if (!requestBody.containsKey("limit")) { | ||
| requestBody.put("limit", ConnectorConstants.DEFAULT_MAX_BATCH_SIZE); | ||
| } | ||
|
|
||
| if (cursor != null) { | ||
| requestBody.put("cursor", cursor); | ||
| } | ||
|
|
||
| Request request = Request.create().withRequestParameters(requestBody); | ||
|
|
||
| ResponseBinary response = getClient().experimental().cdfHttpRequest(requestUri) | ||
| .withRequestBody(request) | ||
| .withHeader(CDF_VERSION_HEADER, CDF_VERSION_VALUE) | ||
| .post(); | ||
|
|
||
| if (!response.getResponse().isSuccessful()) { | ||
| throw new Exception("Failed to list limit values. Response code: " | ||
| + response.getResponse().code() | ||
| + ", message: " + response.getResponse().message()); | ||
| } | ||
|
|
||
| String responseBody = response.getResponseBodyBytes().toStringUtf8(); | ||
| JsonNode root = objectMapper.readTree(responseBody); | ||
|
|
||
| // Parse items | ||
| List<LimitValue> results = new ArrayList<>(); | ||
| JsonNode itemsNode = root.path("items"); | ||
| if (itemsNode.isArray()) { | ||
| for (JsonNode itemNode : itemsNode) { | ||
| results.add(LimitValueParser.parseLimitValue(itemNode)); | ||
| } | ||
| } | ||
|
|
||
| // Check for next cursor | ||
| JsonNode nextCursorNode = root.path("nextCursor"); | ||
| if (nextCursorNode.isTextual() && !nextCursorNode.textValue().isEmpty()) { | ||
| cursor = nextCursorNode.textValue(); | ||
| hasMore = true; | ||
| } else { | ||
| hasMore = false; | ||
| } | ||
|
|
||
| return results; | ||
| } | ||
| } | ||
|
|
||
| @AutoValue.Builder | ||
| abstract static class Builder extends ApiBase.Builder<Builder> { | ||
| abstract LimitValues build(); | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
src/main/java/com/cognite/client/servicesV1/parser/LimitValueParser.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| /* | ||
| * Copyright (c) 2020 Cognite AS | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package com.cognite.client.servicesV1.parser; | ||
|
|
||
| import com.cognite.client.dto.LimitValue; | ||
| import com.cognite.client.servicesV1.util.JsonUtil; | ||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.google.common.collect.ImmutableMap; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| import static com.cognite.client.servicesV1.ConnectorConstants.MAX_LOG_ELEMENT_LENGTH; | ||
|
|
||
| /** | ||
| * This class contains a set of methods to help parsing limit value objects between Cognite API representations | ||
| * (json and proto) and typed objects. | ||
| */ | ||
| public class LimitValueParser { | ||
| static final String logPrefix = "LimitValueParser - "; | ||
| static final ObjectMapper objectMapper = JsonUtil.getObjectMapperInstance(); | ||
|
|
||
| /** | ||
| * Parses a limit value json string to {@code LimitValue} proto object. | ||
| * | ||
| * @param json The JSON string to parse | ||
| * @return The parsed LimitValue object | ||
| * @throws Exception if parsing fails | ||
| */ | ||
| public static LimitValue parseLimitValue(String json) throws Exception { | ||
| JsonNode root = objectMapper.readTree(json); | ||
| return parseLimitValue(root); | ||
| } | ||
|
|
||
| /** | ||
| * Parses a limit value JsonNode to {@code LimitValue} proto object. | ||
| * | ||
| * This overload allows callers that already have a JsonNode to avoid | ||
| * the overhead of converting the node to a string and re-parsing. | ||
| * | ||
| * @param root The JSON node to parse | ||
| * @return The parsed LimitValue object | ||
| * @throws Exception if parsing fails | ||
| */ | ||
| public static LimitValue parseLimitValue(JsonNode root) throws Exception { | ||
arnav-cognite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| LimitValue.Builder builder = LimitValue.newBuilder(); | ||
|
|
||
| // limitId is required | ||
| if (root.path("limitId").isTextual()) { | ||
| builder.setLimitId(root.get("limitId").textValue()); | ||
| } else { | ||
| throw new Exception(logPrefix + "Unable to parse attribute: limitId. Item excerpt: " | ||
| + root.toString().substring(0, Math.min(root.toString().length(), MAX_LOG_ELEMENT_LENGTH))); | ||
| } | ||
|
|
||
| // value is required | ||
| if (root.path("value").isIntegralNumber()) { | ||
| builder.setValue(root.get("value").longValue()); | ||
| } else { | ||
| throw new Exception(logPrefix + "Unable to parse attribute: value. Item excerpt: " | ||
| + root.toString().substring(0, Math.min(root.toString().length(), MAX_LOG_ELEMENT_LENGTH))); | ||
| } | ||
|
|
||
| return builder.build(); | ||
| } | ||
|
|
||
| /** | ||
| * Builds a request item object from {@link LimitValue}. | ||
| * | ||
| * @param element The LimitValue to convert | ||
| * @return A map representing the request body | ||
| */ | ||
| public static Map<String, Object> toRequestInsertItem(LimitValue element) { | ||
| return ImmutableMap.<String, Object>builder() | ||
| .put("limitId", element.getLimitId()) | ||
| .put("value", element.getValue()) | ||
| .build(); | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package com.cognite.client.dto; | ||
|
|
||
| option java_package = "com.cognite.client.dto"; | ||
| option java_multiple_files = true; | ||
|
|
||
| // LimitValue represents a limit value from the Cognite Limits API. | ||
| message LimitValue { | ||
| // The unique identifier for this limit (e.g., "functions.running_calls") | ||
| string limit_id = 1; | ||
|
|
||
| // The current value of the limit | ||
| int64 value = 2; | ||
| } | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.