/**
   * @see io.apiman.gateway.engine.components.IRateLimiterComponent#accept(java.lang.String,
   *     io.apiman.gateway.engine.rates.RateBucketPeriod, int,
   *     io.apiman.gateway.engine.async.IAsyncResultHandler)
   */
  @Override
  public void accept(
      String bucketId,
      RateBucketPeriod period,
      int limit,
      IAsyncResultHandler<RateLimitResponse> handler) {
    RateLimiterBucket bucket = null;
    synchronized (mutex) {
      bucket = (RateLimiterBucket) getCache().get(bucketId);
      if (bucket == null) {
        bucket = new RateLimiterBucket();
        getCache().put(bucketId, bucket);
      }
      bucket.resetIfNecessary(period);

      RateLimitResponse response = new RateLimitResponse();
      if (bucket.getCount() >= limit) {
        response.setAccepted(false);
      } else {
        bucket.setCount(bucket.getCount() + 1);
        bucket.setLast(System.currentTimeMillis());
        response.setAccepted(true);
      }
      int reset = (int) (bucket.getResetMillis(period) / 1000L);
      response.setReset(reset);
      response.setRemaining(limit - bucket.getCount());
      handler.handle(AsyncResultImpl.<RateLimitResponse>create(response));
      getCache().put(bucketId, bucket);
    }
  }
  /**
   * @see io.apiman.gateway.engine.components.IRateLimiterComponent#accept(java.lang.String,
   *     io.apiman.gateway.engine.rates.RateBucketPeriod, long, long,
   *     io.apiman.gateway.engine.async.IAsyncResultHandler)
   */
  @Override
  public void accept(
      final String bucketId,
      final RateBucketPeriod period,
      final long limit,
      final long increment,
      final IAsyncResultHandler<RateLimitResponse> handler) {
    final String id = id(bucketId);

    try {
      Get get = new Get.Builder(getIndexName(), id).type("rateBucket").build(); // $NON-NLS-1$
      JestResult result = getClient().execute(get);
      RateLimiterBucket bucket;
      long version;
      if (result.isSucceeded()) {
        // use the existing bucket
        version = result.getJsonObject().get("_version").getAsLong(); // $NON-NLS-1$
        bucket = result.getSourceAsObject(RateLimiterBucket.class);
      } else {
        // make a new bucket
        version = 0;
        bucket = new RateLimiterBucket();
      }
      bucket.resetIfNecessary(period);

      final RateLimitResponse rlr = new RateLimitResponse();
      if (bucket.getCount() > limit) {
        rlr.setAccepted(false);
      } else {
        rlr.setAccepted(bucket.getCount() < limit);
        bucket.setCount(bucket.getCount() + increment);
        bucket.setLast(System.currentTimeMillis());
      }
      int reset = (int) (bucket.getResetMillis(period) / 1000L);
      rlr.setReset(reset);
      rlr.setRemaining(limit - bucket.getCount());
      updateBucketAndReturn(id, bucket, rlr, version, bucketId, period, limit, increment, handler);
    } catch (Throwable e) {
      handler.handle(AsyncResultImpl.create(e, RateLimitResponse.class));
    }
  }