/**
   * @param in Object input.
   * @return Read collection.
   * @throws IOException If failed.
   * @throws ClassNotFoundException If failed.
   */
  private Collection<Object> readFieldsCollection(ObjectInput in)
      throws IOException, ClassNotFoundException {
    assert fields;

    int size = in.readInt();

    if (size == -1) return null;

    Collection<Object> res = new ArrayList<>(size);

    for (int i = 0; i < size; i++) {
      int size0 = in.readInt();

      Collection<Object> col = new ArrayList<>(size0);

      for (int j = 0; j < size0; j++) col.add(in.readObject());

      assert col.size() == size0;

      res.add(col);
    }

    assert res.size() == size;

    return res;
  }
  /** @throws Exception If failed. */
  public void testClientAffinity() throws Exception {
    GridClientData partitioned = client.data(PARTITIONED_CACHE_NAME);

    Collection<Object> keys = new ArrayList<>();

    keys.addAll(Arrays.asList(Boolean.TRUE, Boolean.FALSE, 1, Integer.MAX_VALUE));

    Random rnd = new Random();
    StringBuilder sb = new StringBuilder();

    // Generate some random strings.
    for (int i = 0; i < 100; i++) {
      sb.setLength(0);

      for (int j = 0; j < 255; j++)
        // Only printable ASCII symbols for test.
        sb.append((char) (rnd.nextInt(0x7f - 0x20) + 0x20));

      keys.add(sb.toString());
    }

    // Generate some more keys to achieve better coverage.
    for (int i = 0; i < 100; i++) keys.add(UUID.randomUUID());

    for (Object key : keys) {
      UUID nodeId = grid(0).mapKeyToNode(PARTITIONED_CACHE_NAME, key).id();

      UUID clientNodeId = partitioned.affinity(key);

      assertEquals(
          "Invalid affinity mapping for REST response for key: " + key, nodeId, clientNodeId);
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("TypeMayBeWeakened")
  @Nullable
  private Collection<Object> unmarshalFieldsCollection(
      @Nullable Collection<byte[]> byteCol, GridCacheContext<K, V> ctx, ClassLoader ldr)
      throws GridException {
    assert ctx != null;
    assert ldr != null;

    Collection<Object> col = unmarshalCollection(byteCol, ctx, ldr);
    Collection<Object> col0 = null;

    if (col != null) {
      col0 = new ArrayList<>(col.size());

      for (Object o : col) {
        List<Object> list = (List<Object>) o;
        List<Object> list0 = new ArrayList<>(list.size());

        for (Object obj : list)
          list0.add(obj != null ? ctx.marshaller().unmarshal((byte[]) obj, ldr) : null);

        col0.add(list0);
      }
    }

    return col0;
  }
    /** {@inheritDoc} */
    @Override
    protected Collection<? extends GridComputeJob> split(int gridSize, Object arg)
        throws GridException {
      Collection<GridComputeJobAdapter> jobs = new ArrayList<>(gridSize);

      this.gridSize = gridSize;

      final String locNodeId = grid.localNode().id().toString();

      for (int i = 0; i < gridSize; i++) {
        jobs.add(
            new GridComputeJobAdapter() {
              @SuppressWarnings("OverlyStrongTypeCast")
              @Override
              public Object execute() {
                try {
                  Thread.sleep(1000);
                } catch (InterruptedException ignored) {
                  Thread.currentThread().interrupt();
                }

                return new GridBiTuple<>(locNodeId, 1);
              }
            });
      }

      return jobs;
    }
  /**
   * Add information about key and version to request.
   *
   * <p>Other version has to be provided if suspect lock is DHT local.
   *
   * @param key Key.
   * @param cand Candidate.
   */
  @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
  void addCandidate(K key, GridCacheDgcLockCandidate cand) {
    Collection<GridCacheDgcLockCandidate> col =
        F.addIfAbsent(map, key, new ArrayList<GridCacheDgcLockCandidate>());

    assert col != null;

    col.add(cand);
  }
    /** {@inheritDoc} */
    @Override
    protected Collection<? extends GridComputeJob> split(int gridSize, String arg)
        throws GridException {
      Collection<GridComputeJobAdapter> jobs = new ArrayList<>(jobCnt);

      for (int i = 0; i < jobCnt; i++) jobs.add(new TestJob());

      return jobs;
    }
  /** {@inheritDoc} */
  @SuppressWarnings("all")
  @Override
  public boolean readFrom(ByteBuffer buf) {
    commState.setBuffer(buf);

    if (!super.readFrom(buf)) return false;

    switch (commState.idx) {
      case 2:
        if (buf.remaining() < 1) return false;

        err = commState.getBoolean();

        commState.idx++;

      case 3:
        if (buf.remaining() < 8) return false;

        futId = commState.getLong();

        commState.idx++;

      case 4:
        if (commState.readSize == -1) {
          if (buf.remaining() < 4) return false;

          commState.readSize = commState.getInt();
        }

        if (commState.readSize >= 0) {
          if (rejectedKeyBytes == null) rejectedKeyBytes = new ArrayList<>(commState.readSize);

          for (int i = commState.readItems; i < commState.readSize; i++) {
            byte[] _val = commState.getByteArray();

            if (_val == BYTE_ARR_NOT_READ) return false;

            rejectedKeyBytes.add((byte[]) _val);

            commState.readItems++;
          }
        }

        commState.readSize = -1;
        commState.readItems = 0;

        commState.idx++;
    }

    return true;
  }
  /** {@inheritDoc} */
  @SuppressWarnings("all")
  @Override
  public boolean readFrom(ByteBuffer buf) {
    commState.setBuffer(buf);

    if (!super.readFrom(buf)) return false;

    switch (commState.idx) {
      case 2:
        if (commState.readSize == -1) {
          if (buf.remaining() < 4) return false;

          commState.readSize = commState.getInt();
        }

        if (commState.readSize >= 0) {
          if (dataBytes == null) dataBytes = new ArrayList<>(commState.readSize);

          for (int i = commState.readItems; i < commState.readSize; i++) {
            byte[] _val = commState.getByteArray();

            if (_val == BYTE_ARR_NOT_READ) return false;

            dataBytes.add((byte[]) _val);

            commState.readItems++;
          }
        }

        commState.readSize = -1;
        commState.readItems = 0;

        commState.idx++;

      case 3:
        byte[] errBytes0 = commState.getByteArray();

        if (errBytes0 == BYTE_ARR_NOT_READ) return false;

        errBytes = errBytes0;

        commState.idx++;

      case 4:
        if (buf.remaining() < 1) return false;

        fields = commState.getBoolean();

        commState.idx++;

      case 5:
        if (buf.remaining() < 1) return false;

        finished = commState.getBoolean();

        commState.idx++;

      case 6:
        if (commState.readSize == -1) {
          if (buf.remaining() < 4) return false;

          commState.readSize = commState.getInt();
        }

        if (commState.readSize >= 0) {
          if (metaDataBytes == null) metaDataBytes = new ArrayList<>(commState.readSize);

          for (int i = commState.readItems; i < commState.readSize; i++) {
            byte[] _val = commState.getByteArray();

            if (_val == BYTE_ARR_NOT_READ) return false;

            metaDataBytes.add((byte[]) _val);

            commState.readItems++;
          }
        }

        commState.readSize = -1;
        commState.readItems = 0;

        commState.idx++;

      case 7:
        commState.idx++;

      case 8:
        if (buf.remaining() < 8) return false;

        reqId = commState.getLong();

        commState.idx++;
    }

    return true;
  }
  /**
   * Add rejected key to response.
   *
   * @param key Evicted key.
   */
  void addRejected(K key) {
    assert key != null;

    rejectedKeys.add(key);
  }