Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/java/com/cognite/client/CogniteClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,17 @@ public Transformations transformations() {
return Transformations.of(this);
}

/**
* Returns {@link LimitValues} representing the Cognite Limit Values API endpoints.
*
* Note: This API is currently in alpha and requires the cdf-version header.
*
* @return The limit values api object.
*/
public LimitValues limitValues() {
return LimitValues.of(this);
}

/**
* Returns the services layer mirroring the Cognite Data Fusion API.
* @return
Expand Down
261 changes: 261 additions & 0 deletions src/main/java/com/cognite/client/LimitValues.java
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 {
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 {
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();
}
}

3 changes: 2 additions & 1 deletion src/main/java/com/cognite/client/config/ResourceType.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@ public enum ResourceType {
TRANSFORMATIONS_JOBS,
TRANSFORMATIONS_JOB_METRICS,
TRANSFORMATIONS_SCHEDULES,
TRANSFORMATIONS_NOTIFICATIONS;
TRANSFORMATIONS_NOTIFICATIONS,
LIMIT_VALUE;
}
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 {
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();
}
}

16 changes: 16 additions & 0 deletions src/main/proto/limit_value.proto
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;
}

Loading