SearchContinuationToken.java
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.search.documents.implementation.models;
import com.azure.core.util.serializer.SerializerEncoding;
import com.azure.search.documents.util.SearchPagedResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
import static com.azure.search.documents.implementation.util.Utility.getDefaultSerializerAdapter;
/**
* Serialization and deserialization of search page continuation token.
*/
public final class SearchContinuationToken {
/**
* Api version which is used by continuation token.
*/
public static final String API_VERSION = "apiVersion";
/**
* Next link which is used by continuation token.
*/
public static final String NEXT_LINK = "nextLink";
/**
* Next page parameters which is used by continuation token.
*/
public static final String NEXT_PAGE_PARAMETERS = "nextPageParameters";
private static final ObjectMapper MAPPER = new ObjectMapper();
private SearchContinuationToken() {
}
/**
* Serialize to search continuation token using {@code apiVersion}, {@code nextLink} and {@link SearchRequest}
*
* @param apiVersion The api version string.
* @param nextLink The next link from search document result. {@link SearchDocumentsResult}
* @param nextPageParameters {@link SearchRequest} The next page parameters which use to fetch next page.
* @return The search encoded continuation token.
*/
public static String serializeToken(String apiVersion, String nextLink, SearchRequest nextPageParameters) {
Objects.requireNonNull(apiVersion);
if (nextLink == null || nextPageParameters == null || nextPageParameters.getSkip() == null) {
return null;
}
String nextParametersString;
try {
nextParametersString = getDefaultSerializerAdapter().serialize(nextPageParameters, SerializerEncoding.JSON);
} catch (IOException ex) {
throw new IllegalStateException("Failed to serialize the search request.");
}
ObjectNode tokenJson = MAPPER.createObjectNode();
tokenJson.put(API_VERSION, apiVersion);
tokenJson.put(NEXT_LINK, nextLink);
tokenJson.put(NEXT_PAGE_PARAMETERS, nextParametersString);
return Base64.getEncoder().encodeToString(tokenJson.toString().getBytes(StandardCharsets.UTF_8));
}
/**
* Deserialize the continuation token to {@link SearchRequest}
*
* @param apiVersion The api version string.
* @param continuationToken The continuation token from {@link SearchPagedResponse}
* @return {@link SearchRequest} The search request used for fetching next page.
*/
@SuppressWarnings("unchecked")
public static SearchRequest deserializeToken(String apiVersion, String continuationToken) {
try {
String decodedToken = new String(Base64.getDecoder().decode(continuationToken), StandardCharsets.UTF_8);
Map<String, String> tokenFields = MAPPER.readValue(decodedToken, Map.class);
if (!apiVersion.equals(tokenFields.get(API_VERSION))) {
throw new IllegalStateException("Continuation token uses invalid apiVersion" + apiVersion);
}
return getDefaultSerializerAdapter().deserialize(tokenFields.get(NEXT_PAGE_PARAMETERS), SearchRequest.class,
SerializerEncoding.JSON);
} catch (IOException e) {
throw new IllegalArgumentException("The continuation token is invalid. Token: " + continuationToken);
}
}
}