com.azure.cosmos.models.CosmosItemResponse Maven / Gradle / Ivy
Show all versions of azure-cosmos Show documentation
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.cosmos.models;
import com.azure.cosmos.BridgeInternal;
import com.azure.cosmos.CosmosDiagnostics;
import com.azure.cosmos.implementation.Constants;
import com.azure.cosmos.implementation.Document;
import com.azure.cosmos.implementation.ImplementationBridgeHelpers;
import com.azure.cosmos.implementation.InternalObjectNode;
import com.azure.cosmos.implementation.ItemDeserializer;
import com.azure.cosmos.implementation.ResourceResponse;
import com.azure.cosmos.implementation.SerializationDiagnosticsContext;
import com.azure.cosmos.implementation.Utils;
import com.azure.cosmos.implementation.apachecommons.lang.tuple.Pair;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull;
/**
* The type Cosmos item response. This contains the item and response methods
*
* @param the type parameter
*/
public class CosmosItemResponse {
private final Class itemClassType;
private final ItemDeserializer itemDeserializer;
// Converting item to volatile to fix Double-checked locking - https://en.wikipedia.org/wiki/Double-checked_locking
// http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
private volatile T item;
private volatile JsonNode itemBodyOverride;
final ResourceResponse resourceResponse;
private InternalObjectNode props;
private final AtomicBoolean hasTrackingIdCalculated = new AtomicBoolean(false);
private boolean hasTrackingId;
private final Supplier hasPayload;
CosmosItemResponse(ResourceResponse response, Class classType, ItemDeserializer itemDeserializer) {
this.itemClassType = classType;
this.resourceResponse = response;
this.itemDeserializer = itemDeserializer;
this.item = null;
this.hasPayload = () -> response.hasPayload();
this.itemBodyOverride = null;
}
private CosmosItemResponse(ResourceResponse response, T item, JsonNode itemBodyOverride, Class classType, ItemDeserializer itemDeserializer) {
this.itemClassType = classType;
this.resourceResponse = response;
this.itemDeserializer = itemDeserializer;
this.item = item;
this.itemBodyOverride = itemBodyOverride;
boolean hasPayloadStaticValue = item != null;
this.hasPayload = () -> hasPayloadStaticValue;
}
/**
* Gets the resource.
*
* @return the resource
*/
@SuppressWarnings("unchecked") // Casting getProperties() to T is safe given T is of InternalObjectNode.
private byte[] getItemAsByteArray() {
if (item != null && this.itemClassType == Utils.byteArrayClass) {
return (byte[])item;
}
JsonNode effectiveJson = this.itemBodyOverride != null
? this.itemBodyOverride
: this.resourceResponse.getBody();
if (effectiveJson == null) {
return null;
}
return effectiveJson.toString().getBytes(StandardCharsets.UTF_8);
}
/**
* Gets the resource.
*
* @return the resource
*/
@SuppressWarnings("unchecked") // Casting getProperties() to T is safe given T is of InternalObjectNode.
public T getItem() {
if (item != null) {
return item;
}
SerializationDiagnosticsContext serializationDiagnosticsContext = BridgeInternal.getSerializationDiagnosticsContext(this.getDiagnostics());
if (item == null) {
synchronized (this) {
if (item == null && hasPayload.get()) {
if (this.itemClassType == Utils.byteArrayClass) {
Instant serializationStartTime = Instant.now();
JsonNode json = this.resourceResponse.getBody();
item = (T) json.toString().getBytes(StandardCharsets.UTF_8);
Instant serializationEndTime = Instant.now();
SerializationDiagnosticsContext.SerializationDiagnostics diagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics(
serializationStartTime,
serializationEndTime,
SerializationDiagnosticsContext.SerializationType.ITEM_DESERIALIZATION
);
serializationDiagnosticsContext.addSerializationDiagnostics(diagnostics);
return item;
} else if (this.itemClassType == String.class) {
Instant serializationStartTime = Instant.now();
JsonNode json = this.resourceResponse.getBody();
item = (T) json.toString();
Instant serializationEndTime = Instant.now();
SerializationDiagnosticsContext.SerializationDiagnostics diagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics(
serializationStartTime,
serializationEndTime,
SerializationDiagnosticsContext.SerializationType.ITEM_DESERIALIZATION
);
serializationDiagnosticsContext.addSerializationDiagnostics(diagnostics);
return item;
} else if (this.itemClassType == InternalObjectNode.class) {
Instant serializationStartTime = Instant.now();
item = (T) getProperties();
Instant serializationEndTime = Instant.now();
SerializationDiagnosticsContext.SerializationDiagnostics diagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics(
serializationStartTime,
serializationEndTime,
SerializationDiagnosticsContext.SerializationType.ITEM_DESERIALIZATION
);
serializationDiagnosticsContext.addSerializationDiagnostics(diagnostics);
return item;
} else {
Instant serializationStartTime = Instant.now();
item = Utils.parse(this.resourceResponse.getBody(), itemClassType, itemDeserializer);
Instant serializationEndTime = Instant.now();
SerializationDiagnosticsContext.SerializationDiagnostics diagnostics = new SerializationDiagnosticsContext.SerializationDiagnostics(
serializationStartTime,
serializationEndTime,
SerializationDiagnosticsContext.SerializationType.ITEM_DESERIALIZATION
);
serializationDiagnosticsContext.addSerializationDiagnostics(diagnostics);
}
return item;
}
}
}
return item;
}
/**
* Gets the itemProperties
*
* @return the itemProperties
*/
InternalObjectNode getProperties() {
ensureInternalObjectNodeInitialized();
return props;
}
int getResponsePayloadLength() {
return this.resourceResponse.getResponsePayloadLength();
}
private void ensureInternalObjectNodeInitialized() {
synchronized (this) {
if (!this.resourceResponse.hasPayload()) {
props = null;
} else {
props = new InternalObjectNode((ObjectNode)this.resourceResponse.getBody());
}
}
}
/**
* Gets the maximum size limit for this entity (in megabytes (MB) for server resources and in count for master
* resources).
*
* @return the max resource quota.
*/
public String getMaxResourceQuota() {
return resourceResponse.getMaxResourceQuota();
}
/**
* Gets the current size of this entity (in megabytes (MB) for server resources and in count for master resources)
*
* @return the current resource quota usage.
*/
public String getCurrentResourceQuotaUsage() {
return resourceResponse.getCurrentResourceQuotaUsage();
}
/**
* Gets the Activity ID for the request.
*
* @return the activity getId.
*/
public String getActivityId() {
return resourceResponse.getActivityId();
}
/**
* Gets the request charge as request units (RU) consumed by the operation.
*
* For more information about the RU and factors that can impact the effective charges please visit
* Request Units in Azure Cosmos DB
*
* @return the request charge.
*/
public double getRequestCharge() {
return resourceResponse.getRequestCharge();
}
/**
* Gets the HTTP status code associated with the response.
*
* @return the status code.
*/
public int getStatusCode() {
return resourceResponse.getStatusCode();
}
/**
* Gets the token used for managing client's consistency requirements.
*
* @return the session token.
*/
public String getSessionToken() {
return resourceResponse.getSessionToken();
}
/**
* Gets the headers associated with the response.
*
* @return the response headers.
*/
public Map getResponseHeaders() {
return resourceResponse.getResponseHeaders();
}
/**
* Gets the diagnostics information for the current request to Azure Cosmos DB service.
*
* @return diagnostics information for the current request to Azure Cosmos DB service.
*/
public CosmosDiagnostics getDiagnostics() {
return resourceResponse.getDiagnostics();
}
/**
* Gets the end-to-end request latency for the current request to Azure Cosmos DB service.
*
* @return end-to-end request latency for the current request to Azure Cosmos DB service.
*/
public Duration getDuration() {
return resourceResponse.getDuration();
}
/**
* Gets the ETag from the response headers.
* This is only relevant when getting response from the server.
*
* Null in case of delete operation.
*
* @return ETag
*/
public String getETag() {
return resourceResponse.getETag();
}
CosmosItemResponse withRemappedStatusCode(
int statusCode,
double additionalRequestCharge,
boolean isContentResponseOnWriteEnabled) {
ResourceResponse mappedResourceResponse =
this.resourceResponse.withRemappedStatusCode(statusCode, additionalRequestCharge);
T payload = null;
JsonNode itemBodyOverride = null;
if (isContentResponseOnWriteEnabled) {
payload = this.getItem();
itemBodyOverride = this.itemBodyOverride;
}
return new CosmosItemResponse<>(
mappedResourceResponse, payload, itemBodyOverride, this.itemClassType, this.itemDeserializer);
}
boolean hasTrackingId(String candidate) {
if (this.hasTrackingIdCalculated.compareAndSet(false, true)) {
SerializationDiagnosticsContext serializationDiagnosticsContext =
BridgeInternal.getSerializationDiagnosticsContext(this.getDiagnostics());
Instant serializationStartTime = Instant.now();
InternalObjectNode itemNode = getProperties();
Instant serializationEndTime = Instant.now();
SerializationDiagnosticsContext.SerializationDiagnostics diagnostics =
new SerializationDiagnosticsContext.SerializationDiagnostics(
serializationStartTime,
serializationEndTime,
SerializationDiagnosticsContext.SerializationType.ITEM_DESERIALIZATION
);
serializationDiagnosticsContext.addSerializationDiagnostics(diagnostics);
return this.hasTrackingId = (itemNode != null && candidate.equals(itemNode.get(Constants.Properties.TRACKING_ID)));
} else {
return this.hasTrackingId;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// the following helper/accessor only helps to access this class outside of this package.//
///////////////////////////////////////////////////////////////////////////////////////////
static void initialize() {
ImplementationBridgeHelpers.CosmosItemResponseHelper.setCosmosItemResponseBuilderAccessor(
new ImplementationBridgeHelpers.CosmosItemResponseHelper.CosmosItemResponseBuilderAccessor() {
public CosmosItemResponse createCosmosItemResponse(CosmosItemResponse response,
Class classType,
ItemDeserializer itemDeserializer) {
return new CosmosItemResponse<>(
response.resourceResponse,
Utils.parse(response.getItemAsByteArray(), classType),
response.itemBodyOverride,
classType, itemDeserializer);
}
@Override
public CosmosItemResponse withRemappedStatusCode(CosmosItemResponse originalResponse,
int newStatusCode,
double additionalRequestCharge,
boolean isContentResponseOnWriteEnabled) {
return originalResponse
.withRemappedStatusCode(newStatusCode, additionalRequestCharge, isContentResponseOnWriteEnabled);
}
public byte[] getByteArrayContent(CosmosItemResponse response) {
return response.getItemAsByteArray();
}
public void setByteArrayContent(CosmosItemResponse response, Pair content) {
response.item = content.getLeft();
response.itemBodyOverride = content.getRight();
}
public ResourceResponse getResourceResponse(CosmosItemResponse response) {
return response.resourceResponse;
}
@Override
public boolean hasTrackingId(CosmosItemResponse response, String candidate) {
checkNotNull(response, "Argument 'response' must not be null.");
checkNotNull(candidate, "Argument 'candidate' must not be null.");
return response.hasTrackingId(candidate);
}
});
}
static { initialize(); }
}