<commit_before>/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.proxy.s3;

import alluxio.client.file.URIStatus;
import alluxio.wire.FileInfo;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * Get bucket result defined in http://docs.aws.amazon.com/AmazonS3/latest/API/v2-RESTBucketGET.html
 * It will be encoded into an XML string to be returned as an error response for the REST call.
 *
 * TODO(chaomin): consider add more required fields in S3 BucketGet API.
 */
@JacksonXmlRootElement(localName = "ListBucketResult")
@JsonPropertyOrder({ "Name", "Prefix", "ContinuationToken", "NextContinuationToken",
    "KeyCount", "MaxKeys", "IsTruncated", "Contents" })
public class ListBucketResult {

  // Name of the bucket.
  private String mName = "";
  // Keys that begin with the indicated prefix.
  private String mPrefix = null;
  // ContinuationToken is included in the response if it was sent with the request.
  private String mContinuationToken = null;
  // Returns the number of keys included in the response. The value is always less than or equal
  // to the mMaxKeys value.
  private int mKeyCount = 0;
  // The maximum number of keys returned in the response body.
  private int mMaxKeys = S3RestUtils.S3_DEFAULT_MAX_KEYS;
  // Specifies whether or not all of the results were returned. If the number of
  // results exceeds that specified by MaxKeys, all of the results might not be returned.
  private boolean mIsTruncated = false;
  // If only partial results are returned (i.e. mIsTruncated = true), this value is set as the
  // next continuation token. The continuation token is the full Alluxio path of the object.
  private String mNextContinuationToken = null;
  // A list of objects with metadata.
  private List<Content> mContents = new ArrayList<>();

  /**
   * Creates an {@link ListBucketResult}.
   */
  public ListBucketResult() {}

  /**
   * Creates an {@link ListBucketResult}.
   *
   * @param bucketName the bucket name
   * @param objectsList a list of {@link URIStatus}, representing the objects
   * @param options the list bucket options
   */
  public ListBucketResult(String bucketName, List<URIStatus> objectsList, ListBucketOptions options)
      throws S3Exception {
    mName = bucketName;
    mKeyCount = 0;
    if (options.getMaxKeys() != null) {
      mMaxKeys = Integer.valueOf(options.getMaxKeys());
    }
    mContents = new ArrayList<>();
    mContinuationToken = options.getContinuationToken();

    Collections.sort(objectsList, new URIStatusComparator());

    int startIndex = 0;
    if (options.getContinuationToken() != null) {
      URIStatus tokenStatus = new URIStatus(new FileInfo().setPath(options.getContinuationToken()));
      startIndex = Collections.binarySearch(objectsList, tokenStatus, new URIStatusComparator());
      if (startIndex == -1) {
        throw new S3Exception("No such continuation token", S3ErrorCode.NO_SUCH_KEY);
      }
    }

    final DateFormat s3DateFormat = new SimpleDateFormat(S3RestUtils.S3_DATE_FORMAT_REGEXP);
    for (int i = startIndex; i < objectsList.size(); i++) {
      URIStatus status = objectsList.get(i);
      String objectKey = status.getPath().substring(mName.length() + 1);
      if (mKeyCount >= mMaxKeys) {
        mIsTruncated = true;
        mNextContinuationToken = objectKey;
        return;
      }
      if (mContinuationToken != null && objectKey.compareTo(mContinuationToken) < 0) {
        continue;
      }
      // TODO(chaomin): set ETag once there's a way to get MD5 hash of an Alluxio file.
      mContents.add(new Content(
          status.getPath().substring(mName.length() + 1),
          s3DateFormat.format(new Date(status.getLastModificationTimeMs())),<commit_msg>Add a TODO for CommonPrefixes and delimiter<commit_after>/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.proxy.s3;

import alluxio.client.file.URIStatus;
import alluxio.wire.FileInfo;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

/**
 * Get bucket result defined in http://docs.aws.amazon.com/AmazonS3/latest/API/v2-RESTBucketGET.html
 * It will be encoded into an XML string to be returned as an error response for the REST call.
 *
 * TODO(chaomin): consider add more required fields in S3 BucketGet API.
 */
@JacksonXmlRootElement(localName = "ListBucketResult")
@JsonPropertyOrder({ "Name", "Prefix", "ContinuationToken", "NextContinuationToken",
    "KeyCount", "MaxKeys", "IsTruncated", "Contents" })
public class ListBucketResult {

  // Name of the bucket.
  private String mName = "";
  // Keys that begin with the indicated prefix.
  private String mPrefix = null;
  // ContinuationToken is included in the response if it was sent with the request.
  private String mContinuationToken = null;
  // Returns the number of keys included in the response. The value is always less than or equal
  // to the mMaxKeys value.
  private int mKeyCount = 0;
  // The maximum number of keys returned in the response body.
  private int mMaxKeys = S3RestUtils.S3_DEFAULT_MAX_KEYS;
  // Specifies whether or not all of the results were returned. If the number of
  // results exceeds that specified by MaxKeys, all of the results might not be returned.
  private boolean mIsTruncated = false;
  // If only partial results are returned (i.e. mIsTruncated = true), this value is set as the
  // next continuation token. The continuation token is the full Alluxio path of the object.
  private String mNextContinuationToken = null;
  // A list of objects with metadata.
  private List<Content> mContents = new ArrayList<>();

  /**
   * Creates an {@link ListBucketResult}.
   */
  public ListBucketResult() {}

  /**
   * Creates an {@link ListBucketResult}.
   *
   * @param bucketName the bucket name
   * @param objectsList a list of {@link URIStatus}, representing the objects
   * @param options the list bucket options
   */
  public ListBucketResult(String bucketName, List<URIStatus> objectsList, ListBucketOptions options)
      throws S3Exception {
    mName = bucketName;
    mKeyCount = 0;
    if (options.getMaxKeys() != null) {
      mMaxKeys = Integer.valueOf(options.getMaxKeys());
    }
    mContents = new ArrayList<>();
    mContinuationToken = options.getContinuationToken();

    Collections.sort(objectsList, new URIStatusComparator());

    int startIndex = 0;
    if (options.getContinuationToken() != null) {
      URIStatus tokenStatus = new URIStatus(new FileInfo().setPath(options.getContinuationToken()));
      startIndex = Collections.binarySearch(objectsList, tokenStatus, new URIStatusComparator());
      if (startIndex == -1) {
        throw new S3Exception("No such continuation token", S3ErrorCode.NO_SUCH_KEY);
      }
    }

    final DateFormat s3DateFormat = new SimpleDateFormat(S3RestUtils.S3_DATE_FORMAT_REGEXP);
    for (int i = startIndex; i < objectsList.size(); i++) {
      URIStatus status = objectsList.get(i);
      String objectKey = status.getPath().substring(mName.length() + 1);
      if (mKeyCount >= mMaxKeys) {
        mIsTruncated = true;
        mNextContinuationToken = objectKey;
        return;
      }
      if (mContinuationToken != null && objectKey.compareTo(mContinuationToken) < 0) {
        continue;
      }
      // TODO(chaomin): set ETag once there's a way to get MD5 hash of an Alluxio file.
      // TODO(chaomin): construct the response with CommonPrefixes when delimiter support is added.
      mContents.add(new Content(
          status.getPath().substring(mName.length() + 1),
          s3DateFormat.format(new Date(status.getLastModificationTimeMs())),
{'fraction_non_alphanumeric': 0.0931174089068826, 'fraction_numerical': 0.005327082889409759, 'mean_word_length': 3.8486570247933884, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 14}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6744874', 'n_tokens_mistral': 2646, 'n_tokens_neox': 2577, 'n_words': 892}