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

com.microsoft.azure.documentdb.internal.AbstractDocumentServiceRequest Maven / Gradle / Ivy

/*
 * Copyright (c) Microsoft Corporation.  All rights reserved.
 */

package com.microsoft.azure.documentdb.internal;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.PartitionKeyRange;
import com.microsoft.azure.documentdb.internal.directconnectivity.StoreReadResult;
import com.microsoft.azure.documentdb.internal.directconnectivity.StoreResponse;
import com.microsoft.azure.documentdb.internal.routing.PartitionKeyRangeIdentity;
import com.microsoft.azure.documentdb.ClientSideRequestStatistics;

/**
 * This is core Transport/Connection agnostic request to the Azure Cosmos DB database service.
 */
public class AbstractDocumentServiceRequest {
    
    private final String resourceId;
    private final ResourceType resourceType;
    private final String path;
    private final Map headers;
    private volatile String continuation;
    private boolean isMedia = false;
    private final boolean isNameBased;
    private final OperationType operationType;
    private final String resourceAddress;
    private volatile boolean forceNameCacheRefresh;
    private volatile boolean forceAddressRefresh;
    private volatile boolean forcePartitionKeyRangeRefresh;
    private volatile VectorSessionToken sessionToken;
    private volatile URI endpointOverride = null;
    private final String activityId;
    private volatile RequestChargeTracker requestChargeTracker;
    private volatile String resourceFullName;
    private volatile StoreReadResult quorumSelectedStoreResponse;
    private volatile long quorumSelectedLSN;
    private volatile long globalCommittedSelectedLSN;
    private volatile StoreResponse globalStrongWriteResponse;
    private volatile ConsistencyLevel originalRequestConsistencyLevel;
    private volatile String originalSessionToken;
    private volatile String resolvedCollectionRid;
    private volatile PartitionKeyRangeIdentity partitionKeyRangeIdentity;
    private volatile PartitionKeyRange resolvedPartitionKeyRange;
    private volatile Integer defaultReplicaIndex;
    private Boolean usePreferredLocations;
    private Integer locationIndexToRoute;
    private URI locationEndpointToRoute;
    private boolean shouldClearSessionTokenOnSessionReadFailure;
    private ClientSideRequestStatistics clientSideRequestStatistics;
    private String httpMethod;
    private boolean isUserProvidedPartitionKeyRangeIdentity;

    /**
     * Creates a AbstractDocumentServiceRequest
     *
     * @param operationType     the operation type.
     * @param resourceId        the resource id.
     * @param resourceType      the resource type.
     * @param path              the path.
     * @param headers           the headers
     */
    protected AbstractDocumentServiceRequest(OperationType operationType,
            String resourceId,
            ResourceType resourceType,
            String path,
            Map headers) {
        this.operationType = operationType;
        this.resourceType = resourceType;
        this.path = path;
        this.sessionToken = null;
        this.headers = headers != null ? headers : new HashMap();
        this.isNameBased = Utils.isNameBased(path);
        this.activityId = Utils.getTimeBasedRandomUUID().toString();
        if (!this.isNameBased) {
            if (resourceType == ResourceType.Media) {
                this.resourceId = getAttachmentIdFromMediaId(resourceId);
            } else {
                this.resourceId = resourceId;
            }
            this.resourceAddress = resourceId;
        } else {
            this.resourceAddress = this.path;
            this.resourceId = null;
        }
    }

    protected static String extractIdFromUri(String str)
    {
        final char separatorChar = '/';
        int len = str.length();
        if (len != 0 && str.charAt(len - 1) == separatorChar) {
            --len;
        }

        if (len == 0) {
            return "";
        }

        int ridStartIndex = 1, ridEndIndex = 0; // ridEndIndex will be one out
        boolean isResourceType = true;
        boolean resourceIdFound = false;
        for (int i = 1; i < len; i++) {
            if (str.charAt(i) == separatorChar) {
                resourceIdFound = true;
                isResourceType = !isResourceType;
                if (!isResourceType) {
                    ridStartIndex = i + 1;
                } else {
                    ridEndIndex = i;
                }
            }
        }

        if (! resourceIdFound) {
            // case like /dbs
            return "";
        }

        if (ridEndIndex <= ridStartIndex) {
            ridEndIndex = len;
        }

        return str.substring(ridStartIndex, ridEndIndex);
    }

    static String getAttachmentIdFromMediaId(String mediaId) {
        // '/' was replaced with '-'.
        byte[] buffer = Base64.decodeBase64(mediaId.replace('-', '/').getBytes());

        final int resoureIdLength = 20;
        String attachmentId;

        if (buffer.length > resoureIdLength) {
            // We are cuting off the storage index.
            byte[] newBuffer = new byte[resoureIdLength];
            System.arraycopy(buffer, 0, newBuffer, 0, resoureIdLength);
            attachmentId = Utils.encodeBase64String(newBuffer).replace('/', '-');
        } else {
            attachmentId = mediaId;
        }

        return attachmentId;
    }

    /**
     * Gets the resource id.
     *
     * @return the resource id.
     */
    public String getResourceId() {
        return this.resourceId;
    }

    /**
     * Gets the resource type.
     *
     * @return the resource type.
     */
    public ResourceType getResourceType() {
        return this.resourceType;
    }

    /**
     * Gets the path.
     *
     * @return the path.
     */
    public String getPath() {
        return this.path;
    }

    /**
     * Gets the request headers.
     *
     * @return the request headers.
     */
    public Map getHeaders() {
        return this.headers;
    }

    /**
     * Gets the continuation.
     *
     * @return the continuation.
     */
    public String getContinuation() {
        return this.continuation;
    }

    public void setContinuation(String continuation) {
        this.continuation = continuation;
    }

    public boolean getIsMedia() {
        return this.isMedia;
    }

    public void setIsMedia(boolean isMedia) {
        this.isMedia = isMedia;
    }

    public boolean getIsNameBased() {
        return this.isNameBased;
    }

    public OperationType getOperationType() {
        return this.operationType;
    }

    public String getResourceAddress() {
        return resourceAddress;
    }

    /**
     * Check whether the name caches should be refreshed or not. This is used to trigger named cached refreshes
     * according to certain response from the backend. Name caches include collection cache, and partition key range
     * routing map.
     *
     * @return a boolean value indicating whether the name caches should be refreshed during the request
     */
    public boolean isForceNameCacheRefresh() {
        return this.forceNameCacheRefresh;
    }

    /**
     * Sets the value whether the name caches should be refreshed or not. This flag is used to trigger named cached
     * refreshes according to certain response from the backend. Name caches include the collection cache.
     *
     * @param forceNameCacheRefresh a boolean value indicating whether the name caches should be refreshed during the
     *                              request
     */
    public void setForceNameCacheRefresh(boolean forceNameCacheRefresh) {
        this.forceNameCacheRefresh = forceNameCacheRefresh;
    }

    /**
     * Gets whether the address cache should be refreshed or not. This flag is used to trigger the address caches which
     * include read, write, and alternate write address cache.
     *
     * @return a boolean indicating if the address caches should be refreshed or not
     */
    public boolean isForceAddressRefresh() {
        return this.forceAddressRefresh;
    }

    /**
     * Sets whether the address cache should be refreshed or not. This flag is used to trigger the address caches which
     * include read, write, and alternate write address cache.
     *
     * @param forceAddressRefresh a boolean indicating if the address caches should be refreshed or not
     */
    public void setForceAddressRefresh(boolean forceAddressRefresh) {
        this.forceAddressRefresh = forceAddressRefresh;
    }

    /**
     * Sets whether the partitionKeyRange cache should be refreshed or not. This flag is used to trigger the partitionKeyRange caches which
     * include read, write, and alternate write partitionKeyRange cache.
     *
     * @param forcePartitionKeyRangeRefresh a boolean indicating if the partitionKeyRange caches should be refreshed or not
     */
    public void setForcePartitionKeyRangeRefresh(boolean forcePartitionKeyRangeRefresh) {
        this.forcePartitionKeyRangeRefresh = forcePartitionKeyRangeRefresh;
    }

    /**
     * Gets whether the partitionKeyRange cache should be refreshed or not. This flag is used to trigger the partitionKeyRange caches which
     * include read, write, and alternate write partitionKeyRange cache.
     *
     * @return a boolean indicating if the partitionKeyRange caches should be refreshed or not
     */
    public boolean isForcePartitionKeyRangeRefresh() {
        return this.forcePartitionKeyRangeRefresh;
    }

    public VectorSessionToken getSessionToken() {
        return this.sessionToken;
    }

    public void setSessionToken(VectorSessionToken sessionToken) {
        this.sessionToken = sessionToken;
    }

    public URI getEndpointOverride() {
        return this.endpointOverride;
    }

    public void setEndpointOverride(URI endpointOverride) {
        this.endpointOverride = endpointOverride;
    }

    public String getActivityId() {
        return this.activityId;
    }

    public RequestChargeTracker getRequestChargeTracker() {
        return requestChargeTracker;
    }

    public void setRequestChargeTracker(RequestChargeTracker requestChargeTracker) {
        this.requestChargeTracker = requestChargeTracker;
    }

    public String getResourceFullName() {
        if (this.isNameBased) {
            String trimmedPath = Utils.trimBeginingAndEndingSlashes(this.path);
            String[] segments = StringUtils.split(trimmedPath, '/');

            if (segments.length % 2 == 0) {
                // if path has even segments, it is the individual resource
                // like dbs/db1/colls/coll1
                if (Utils.IsResourceType(segments[segments.length - 2])) {
                    this.resourceFullName = trimmedPath;
                }
            } else {
                // if path has odd segments, get the parent(dbs/db1 from
                // dbs/db1/colls)
                if (Utils.IsResourceType(segments[segments.length - 1])) {
                    this.resourceFullName = trimmedPath.substring(0, trimmedPath.lastIndexOf("/"));
                }
            }
        } else {
            this.resourceFullName = this.getResourceId().toLowerCase();
        }

        return this.resourceFullName;
    }

    public String getResolvedCollectionRid() {
        return resolvedCollectionRid;
    }

    public void setResolvedCollectionRid(String resolvedCollectionRid) {
        this.resolvedCollectionRid = resolvedCollectionRid;
    }

    public PartitionKeyRangeIdentity getPartitionKeyRangeIdentity() {
        return partitionKeyRangeIdentity;
    }

    public void routeTo(PartitionKeyRangeIdentity partitionKeyRangeIdentity) {
        this.setPartitionKeyRangeIdentity(partitionKeyRangeIdentity);
    }

    public void setPartitionKeyRangeIdentity(PartitionKeyRangeIdentity partitionKeyRangeIdentity) {
        this.partitionKeyRangeIdentity = partitionKeyRangeIdentity;
        if (partitionKeyRangeIdentity != null) {
            this.headers.put(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeIdentity.toHeader());
        } else {
            this.headers.remove(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID);
        }
    }

    public PartitionKeyRange getResolvedPartitionKeyRange() {
        return resolvedPartitionKeyRange;
    }

    public void setResolvedPartitionKeyRange(PartitionKeyRange resolvedPartitionKeyRange) {
        this.resolvedPartitionKeyRange = resolvedPartitionKeyRange;
    }

    public long getQuorumSelectedLSN() {
        return quorumSelectedLSN;
    }

    public void setQuorumSelectedLSN(long quorumSelectedLSN) {
        this.quorumSelectedLSN = quorumSelectedLSN;
    }

    public ConsistencyLevel getOriginalRequestConsistencyLevel() {
        return originalRequestConsistencyLevel;
    }

    public void setOriginalRequestConsistencyLevel(ConsistencyLevel originalRequestConsistencyLevel) {
        this.originalRequestConsistencyLevel = originalRequestConsistencyLevel;
    }

    public StoreResponse getGlobalStrongWriteResponse() {
        return globalStrongWriteResponse;
    }

    public void setGlobalStrongWriteResponse(StoreResponse globalStrongWriteResponse) {
        this.globalStrongWriteResponse = globalStrongWriteResponse;
    }

    public long getGlobalCommittedSelectedLSN() {
        return globalCommittedSelectedLSN;
    }

    public void setGlobalCommittedSelectedLSN(long globalCommittedSelectedLSN) {
        this.globalCommittedSelectedLSN = globalCommittedSelectedLSN;
    }

    public String getOriginalSessionToken() {
        return originalSessionToken;
    }

    public void setOriginalSessionToken(String originalSessionToken) {
        this.originalSessionToken = originalSessionToken;
    }

    public StoreReadResult getQuorumSelectedStoreResponse() {
        return quorumSelectedStoreResponse;
    }

    public void setQuorumSelectedStoreResponse(StoreReadResult quorumSelectedStoreResponse) {
        this.quorumSelectedStoreResponse = quorumSelectedStoreResponse;
    }

    public void setDefaultReplicaIndex(Integer defaultReplicaIndex) {
        this.defaultReplicaIndex = defaultReplicaIndex;
    }

    public Integer getDefaultReplicaIndex() {
        return defaultReplicaIndex;
    }

    public boolean isChangeFeedRequest() {
        return this.headers.containsKey(HttpConstants.HttpHeaders.A_IM);
    }

    public boolean isWritingToMaster() {
        return operationType.isWriteOperation() && resourceType.isMasterResource();
    }

    public boolean isReadingFromMaster() {
        if (resourceType == ResourceType.Offer ||
                resourceType == ResourceType.Database ||
                resourceType == ResourceType.User ||
                resourceType == ResourceType.Permission ||
                resourceType == ResourceType.Topology ||
                resourceType == ResourceType.DatabaseAccount ||
                resourceType == ResourceType.PartitionKeyRange ||
                (resourceType == ResourceType.DocumentCollection
                        && (operationType == OperationType.ReadFeed
                        || operationType == OperationType.Query
                        || operationType == OperationType.SqlQuery))) {
            return true;
        }
        return false;
    }

    public boolean isReadOnlyRequest() {
        return Utils.isReadOnlyOperation(this.operationType);
    }

    public boolean shouldClearSessionTokenOnSessionReadFailure() {
        return this.shouldClearSessionTokenOnSessionReadFailure;
    }

    public void setShouldClearSessionTokenOnSessionReadFailure(boolean value) {
        this.shouldClearSessionTokenOnSessionReadFailure = value;
    }

    public Boolean getUsePreferredLocations() {
        return this.usePreferredLocations;
    }

    public void setUsePreferredLocations(Boolean value) {
        this.usePreferredLocations = value;
    }

    public Integer getLocationIndexToRoute() {
        return this.locationIndexToRoute;
    }

    public void setLocationIndexToRoute(Integer value) {
        this.locationIndexToRoute = value;
    }

    public URI getLocationEndpointToRoute() {
        return this.locationEndpointToRoute;
    }

    public void setLocationEndpointToRoute(URI value) {
        this.locationEndpointToRoute = value;
    }

    public ClientSideRequestStatistics getClientSideRequestStatistics() {
        return clientSideRequestStatistics;
    }

    public void setClientSideRequestStatistics(ClientSideRequestStatistics clientSideRequestStatistics) {
        this.clientSideRequestStatistics = clientSideRequestStatistics;
    }

    /**
     * Sets routing directive for GlobalEndpointManager to resolve
     * the request to endpoint based on location index
     *
     * @param locationIndex            Index of the location to which the request should be routed.
     * @param usePreferredLocations    Use preferred locations to route request.
     */
    public void routeToLocation(int locationIndex, boolean usePreferredLocations) {
        this.setLocationIndexToRoute(locationIndex);
        this.setUsePreferredLocations(usePreferredLocations);
        this.setLocationEndpointToRoute(null);
    }

    /**
     * Sets location-based routing directive for GlobalEndpointManager to resolve
     * the request to given locationEndpoint
     *
     * @param locationEndpoint      Location endpoint to which the request should be routed.
     */
    public void routeToLocation(URI locationEndpoint) {
        this.setLocationEndpointToRoute(locationEndpoint);
        this.setLocationIndexToRoute(null);
        this.setUsePreferredLocations(null);
    }

    /**
     * Clears location-based routing directive
     */
    public void clearRouteToLocation() {
        this.setLocationIndexToRoute(null);
        this.setLocationEndpointToRoute(null);
        this.setUsePreferredLocations(null);
    }
    
    public String getHttpMethod() {
        return httpMethod;
    }

    public void setHttpMethod(String httpMethod) {
        this.httpMethod = httpMethod;
    }

    boolean isUserProvidedPartitionKeyRangeIdentity() {
        return isUserProvidedPartitionKeyRangeIdentity;
    }

    void setUserProvidedPartitionKeyRangeIdentity(boolean userProvidedPartitionKeyRangeIdentity) {
        isUserProvidedPartitionKeyRangeIdentity = userProvidedPartitionKeyRangeIdentity;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy