/**
   * Sets JEXL context variable value and returns {@code this}.
   *
   * @param var Name of the variable in JEXL context (new or existing).
   * @param val Value to be set or overridden in JEXL context.
   * @return This predicate so that this call can be chained.
   */
  public GridJexlPredicate2<T1, T2> with(String var, @Nullable Object val) {
    A.notNull(var, "var");

    map.put(var, val);

    return this;
  }
  /**
   * Sets JEXL context variables' values and returns {@code this}.
   *
   * @param vals Set of tuples representing JEXL context to be bound. First element in the tuple
   *     represents the name and the second element represents its value in the context.
   * @return This predicate so that this call can be chained.
   */
  public GridJexlPredicate2<T1, T2> with(GridTuple2<String, Object>... vals) {
    for (GridTuple2<String, Object> t : vals) {
      map.put(t.get1(), t.get2());
    }

    return this;
  }
  /** {@inheritDoc} */
  @Override
  public Map<?, ?> waitForAttributes(Collection<?> keys, long timeout) throws InterruptedException {
    A.notNull(keys, "keys");

    if (keys.isEmpty()) return Collections.emptyMap();

    if (timeout == 0) timeout = Long.MAX_VALUE;

    long now = System.currentTimeMillis();

    // Prevent overflow.
    long end = now + timeout < 0 ? Long.MAX_VALUE : now + timeout;

    // Don't wait longer than session timeout.
    if (end > endTime) end = endTime;

    synchronized (mux) {
      while (!closed && !attrs.keySet().containsAll(keys) && now < end) {
        mux.wait(end - now);

        now = System.currentTimeMillis();
      }

      if (closed) throw new InterruptedException("Session was closed: " + this);

      Map<Object, Object> retVal = new HashMap<Object, Object>(keys.size());

      for (Object key : keys) retVal.put(key, attrs.get(key));

      return retVal;
    }
  }
  /** {@inheritDoc} */
  @Override
  public void setAttribute(Object key, @Nullable Object val) {
    A.notNull(key, "key");

    synchronized (attrs) {
      attrs.put(key, val);
    }
  }