/** {@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;
    }
  /** {@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;
  }
  /** @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);
    }
  }
  /** @throws Exception If failed. */
  public void testProjectionRun() throws Exception {
    GridClientCompute dflt = client.compute();

    Collection<? extends GridClientNode> nodes = dflt.nodes();

    assertEquals(NODES_CNT, nodes.size());

    for (int i = 0; i < NODES_CNT; i++) {
      Grid g = grid(i);

      assert g != null;

      GridClientNode clientNode = dflt.node(g.localNode().id());

      assertNotNull("Client node for " + g.localNode().id() + " was not found", clientNode);

      GridClientCompute prj = dflt.projection(clientNode);

      String res = prj.execute(TestTask.class.getName(), null);

      assertNotNull(res);

      assertEquals(g.localNode().id().toString(), res);
    }
  }
  /**
   * 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;
    }
  /** @throws Exception If failed. */
  public void testTopologyListener() throws Exception {
    final Collection<UUID> added = new ArrayList<>(1);
    final Collection<UUID> rmvd = new ArrayList<>(1);

    final CountDownLatch addedLatch = new CountDownLatch(1);
    final CountDownLatch rmvLatch = new CountDownLatch(1);

    assertEquals(NODES_CNT, client.compute().refreshTopology(false, false).size());

    GridClientTopologyListener lsnr =
        new GridClientTopologyListener() {
          @Override
          public void onNodeAdded(GridClientNode node) {
            added.add(node.nodeId());

            addedLatch.countDown();
          }

          @Override
          public void onNodeRemoved(GridClientNode node) {
            rmvd.add(node.nodeId());

            rmvLatch.countDown();
          }
        };

    client.addTopologyListener(lsnr);

    try {
      Grid g = startGrid(NODES_CNT + 1);

      UUID id = g.localNode().id();

      assertTrue(addedLatch.await(2 * TOP_REFRESH_FREQ, MILLISECONDS));

      assertEquals(1, added.size());
      assertEquals(id, F.first(added));

      stopGrid(NODES_CNT + 1);

      assertTrue(rmvLatch.await(2 * TOP_REFRESH_FREQ, MILLISECONDS));

      assertEquals(1, rmvd.size());
      assertEquals(id, F.first(rmvd));
    } finally {
      client.removeTopologyListener(lsnr);

      stopGrid(NODES_CNT + 1);
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("all")
  @Override
  public boolean writeTo(ByteBuffer buf) {
    commState.setBuffer(buf);

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

    if (!commState.typeWritten) {
      if (!commState.putByte(directType())) return false;

      commState.typeWritten = true;
    }

    switch (commState.idx) {
      case 2:
        if (!commState.putBoolean(err)) return false;

        commState.idx++;

      case 3:
        if (!commState.putLong(futId)) return false;

        commState.idx++;

      case 4:
        if (rejectedKeyBytes != null) {
          if (commState.it == null) {
            if (!commState.putInt(rejectedKeyBytes.size())) return false;

            commState.it = rejectedKeyBytes.iterator();
          }

          while (commState.it.hasNext() || commState.cur != NULL) {
            if (commState.cur == NULL) commState.cur = commState.it.next();

            if (!commState.putByteArray((byte[]) commState.cur)) return false;

            commState.cur = NULL;
          }

          commState.it = null;
        } else {
          if (!commState.putInt(-1)) return false;
        }

        commState.idx++;
    }

    return true;
  }
  /** {@inheritDoc} */
  @SuppressWarnings("TypeMayBeWeakened")
  @Nullable
  private Collection<byte[]> marshalFieldsCollection(
      @Nullable Collection<Object> col, GridCacheContext<K, V> ctx) throws GridException {
    assert ctx != null;

    if (col == null) return null;

    Collection<List<Object>> col0 = new ArrayList<>(col.size());

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

      for (GridIndexingEntity<?> ent : list) {
        if (ent.bytes() != null) list0.add(ent.bytes());
        else {
          if (ctx.deploymentEnabled()) prepareObject(ent.value(), ctx);

          list0.add(CU.marshal(ctx, ent.value()));
        }
      }

      col0.add(list0);
    }

    return marshalCollection(col0, ctx);
  }
  /**
   * @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 testAffinityExecute() throws Exception {
    GridClientCompute dflt = client.compute();

    GridClientData data = client.data(PARTITIONED_CACHE_NAME);

    Collection<? extends GridClientNode> nodes = dflt.nodes();

    assertEquals(NODES_CNT, nodes.size());

    for (int i = 0; i < NODES_CNT; i++) {
      Grid g = grid(i);

      assert g != null;

      int affinityKey = -1;

      for (int key = 0; key < 10000; key++) {
        if (g.localNode().id().equals(data.affinity(key))) {
          affinityKey = key;

          break;
        }
      }

      if (affinityKey == -1)
        throw new Exception("Unable to found key for which node is primary: " + g.localNode().id());

      GridClientNode clientNode = dflt.node(g.localNode().id());

      assertNotNull("Client node for " + g.localNode().id() + " was not found", clientNode);

      String res =
          dflt.affinityExecute(TestTask.class.getName(), PARTITIONED_CACHE_NAME, affinityKey, null);

      assertNotNull(res);

      assertEquals(g.localNode().id().toString(), res);
    }
  }
  /** {@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;
  }
  /**
   * @param out Object output.
   * @throws IOException If failed.
   */
  @SuppressWarnings("TypeMayBeWeakened")
  private void writeFieldsCollection(ObjectOutput out) throws IOException {
    assert fields;

    out.writeInt(data != null ? data.size() : -1);

    if (data == null) return;

    for (Object o : data) {
      List<GridIndexingEntity<?>> list = (List<GridIndexingEntity<?>>) o;

      out.writeInt(list.size());

      for (GridIndexingEntity<?> idxEnt : list) {
        try {
          out.writeObject(idxEnt.value());
        } catch (GridSpiException e) {
          throw new IOException("Failed to write indexing entity: " + idxEnt, e);
        }
      }
    }
  }
  /** {@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;
  }
  /** @throws Exception If failed. */
  public void testEmptyProjections() throws Exception {
    final GridClientCompute dflt = client.compute();

    Collection<? extends GridClientNode> nodes = dflt.nodes();

    assertEquals(NODES_CNT, nodes.size());

    Iterator<? extends GridClientNode> iter = nodes.iterator();

    final GridClientCompute singleNodePrj = dflt.projection(Collections.singletonList(iter.next()));

    final GridClientNode second = iter.next();

    final GridClientPredicate<GridClientNode> noneFilter =
        new GridClientPredicate<GridClientNode>() {
          @Override
          public boolean apply(GridClientNode node) {
            return false;
          }
        };

    final GridClientPredicate<GridClientNode> targetFilter =
        new GridClientPredicate<GridClientNode>() {
          @Override
          public boolean apply(GridClientNode node) {
            return node.nodeId().equals(second.nodeId());
          }
        };

    GridTestUtils.assertThrows(
        log(),
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            return dflt.projection(noneFilter).log(-1, -1);
          }
        },
        GridServerUnreachableException.class,
        null);

    GridTestUtils.assertThrows(
        log(),
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            return singleNodePrj.projection(second);
          }
        },
        GridClientException.class,
        null);

    GridTestUtils.assertThrows(
        log(),
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            return singleNodePrj.projection(targetFilter);
          }
        },
        GridClientException.class,
        null);
  }
  /**
   * Add rejected key to response.
   *
   * @param key Evicted key.
   */
  void addRejected(K key) {
    assert key != null;

    rejectedKeys.add(key);
  }