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

com.couchbase.client.java.kv.GetResult Maven / Gradle / Ivy

There is a newer version: 3.7.5
Show newest version
/*
 * Copyright (c) 2018 Couchbase, Inc.
 *
 * 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.couchbase.client.java.kv;

import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.deps.io.netty.buffer.ByteBuf;
import com.couchbase.client.core.deps.io.netty.buffer.ByteBufUtil;
import com.couchbase.client.core.deps.io.netty.buffer.Unpooled;
import com.couchbase.client.core.error.CasMismatchException;
import com.couchbase.client.core.msg.kv.CodecFlags;
import com.couchbase.client.core.api.kv.CoreGetResult;
import com.couchbase.client.java.codec.Transcoder;
import com.couchbase.client.java.codec.TypeRef;
import com.couchbase.client.java.json.JsonArray;
import com.couchbase.client.java.json.JsonObject;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

import static com.couchbase.client.core.logging.RedactableArgument.redactUser;

/**
 * Returned from all kinds of KeyValue Get operation to fetch a document or a subset of it.
 *
 * @since 3.0.0
 */
public class GetResult {

  /**
   * The encoded content when loading the document.
   */
  protected final byte[] content;

  /**
   * The flags from the kv operation.
   */
  protected final int flags;

  /**
   * The CAS of the fetched document.
   */
  private final long cas;

  /**
   * The expiry if fetched and present.
   */
  private final Optional expiry;

  /**
   * The default transcoder which should be used.
   */
  protected final Transcoder transcoder;

  /**
   * Creates a new {@link GetResult}.
   *
   * @param cas the cas from the doc.
   * @param expiry the expiry if fetched from the doc.
   */
  @Stability.Internal
  public GetResult(final byte[] content, final int flags, final long cas, final Optional expiry, Transcoder transcoder) {
    this.cas = cas;
    this.content = content;
    this.flags = flags;
    this.expiry = expiry;
    this.transcoder = transcoder;
  }

  @Stability.Internal
  public GetResult(CoreGetResult core, Transcoder transcoder) {
    this(core.content(), core.flags(), core.cas(), Optional.ofNullable(core.expiry()), transcoder);
  }

  /**
   * Returns the CAS value of document at the time of loading.
   * 

* The CAS value is an opaque identifier which is associated with a specific state of the document on the server. It * can be used during a subsequent mutation to make sure that the document has not been modified in the meantime. *

* If document on the server has been modified in the meantime the SDK will raise a {@link CasMismatchException}. In * this case the caller is expected to re-do the whole "fetch-modify-update" cycle again. Please refer to the * SDK documentation for more information on CAS mismatches and subsequent retries. */ public long cas() { return cas; } /** * If the document has an expiry, returns length of time between * the start of the epoch and the point in time when the loaded * document expires. *

* In other words, the number of seconds in the returned duration * is equal to the epoch second when the document expires. *

* NOTE: This method always returns an empty Optional unless * the Get request was made using {@link GetOptions#withExpiry(boolean)} * set to true. */ @Deprecated public Optional expiry() { return expiry.map(instant -> Duration.ofSeconds(instant.getEpochSecond())); } /** * If the document has an expiry, returns the point in time when the loaded * document expires. *

* NOTE: This method always returns an empty Optional unless * the Get request was made using {@link GetOptions#withExpiry(boolean)} * set to true. */ public Optional expiryTime() { return expiry; } /** * Decodes the content of the document into a {@link JsonObject}. */ public JsonObject contentAsObject() { return contentAs(JsonObject.class); } /** * Decodes the content of the document into a {@link JsonArray}. */ public JsonArray contentAsArray() { return contentAs(JsonArray.class); } /** * Decodes the content of the document into an instance of the target class. * * @param target the target class to decode the encoded content into. */ public T contentAs(final Class target) { return transcoder.decode(target, content, flags); } /** * Decodes the content of the document into an instance of the target type. * Example usage: *

   * List<String> strings = result.contentAs(new TypeRef<List<String>>(){});
   * 
* * @param target the type to decode the encoded content into. */ public T contentAs(final TypeRef target) { return transcoder.decode(target, content, flags); } /** * Returns the raw bytes of the document content. * * @return the document content as a byte array */ @Stability.Uncommitted public byte[] contentAsBytes() { return content; } @Override public String toString() { return "GetResult{" + "content=" + redactUser(convertContentToString(content, flags)) + ", flags=0x" + Integer.toHexString(flags) + ", cas=0x" + Long.toHexString(cas) + ", expiry=" + expiry + '}'; } /** * Converts the content to a string representation if possible (for toString). */ static String convertContentToString(final byte[] content, final int flags) { if (content.length == 0) { return ""; } boolean printable = CodecFlags.hasCommonFormat(flags, CodecFlags.JSON_COMMON_FLAGS) || CodecFlags.hasCommonFormat(flags, CodecFlags.STRING_COMMON_FLAGS) || (flags == 0 && content[0] == '{') ; if (printable) { return new String(content, StandardCharsets.UTF_8); } else { ByteBuf buf = Unpooled.wrappedBuffer(content); String result = ByteBufUtil.prettyHexDump(buf); buf.release(); return "\n" + result + "\n"; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GetResult getResult = (GetResult) o; return flags == getResult.flags && cas == getResult.cas && Arrays.equals(content, getResult.content) && Objects.equals(expiry, getResult.expiry) && Objects.equals(transcoder, getResult.transcoder); } @Override public int hashCode() { int result = Objects.hash(flags, cas, expiry, transcoder); result = 31 * result + Arrays.hashCode(content); return result; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy