public Response get()

in hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java [106:293]


  public Response get(
      @PathParam("bucket") String bucketName,
      @QueryParam("delimiter") String delimiter,
      @QueryParam("encoding-type") String encodingType,
      @QueryParam("marker") String marker,
      @DefaultValue("1000") @QueryParam("max-keys") int maxKeys,
      @QueryParam("prefix") String prefix,
      @QueryParam("continuation-token") String continueToken,
      @QueryParam("start-after") String startAfter,
      @QueryParam("uploads") String uploads,
      @QueryParam("acl") String aclMarker,
      @QueryParam("key-marker") String keyMarker,
      @QueryParam("upload-id-marker") String uploadIdMarker,
      @DefaultValue("1000") @QueryParam("max-uploads") int maxUploads,
      @Context HttpHeaders hh) throws OS3Exception, IOException {
    long startNanos = Time.monotonicNowNanos();
    S3GAction s3GAction = S3GAction.GET_BUCKET;
    PerformanceStringBuilder perf = new PerformanceStringBuilder();

    Iterator<? extends OzoneKey> ozoneKeyIterator = null;
    ContinueToken decodedToken =
        ContinueToken.decodeFromString(continueToken);
    OzoneBucket bucket = null;

    try {
      if (aclMarker != null) {
        s3GAction = S3GAction.GET_ACL;
        S3BucketAcl result = getAcl(bucketName);
        getMetrics().updateGetAclSuccessStats(startNanos);
        AUDIT.logReadSuccess(
            buildAuditMessageForSuccess(s3GAction, getAuditParameters()));
        return Response.ok(result, MediaType.APPLICATION_XML_TYPE).build();
      }

      if (uploads != null) {
        s3GAction = S3GAction.LIST_MULTIPART_UPLOAD;
        return listMultipartUploads(bucketName, prefix, keyMarker, uploadIdMarker, maxUploads);
      }

      if (prefix == null) {
        prefix = "";
      }

      // Assign marker to startAfter. for the compatibility of aws api v1
      if (startAfter == null && marker != null) {
        startAfter = marker;
      }

      // If continuation token and start after both are provided, then we
      // ignore start After
      String prevKey = continueToken != null ? decodedToken.getLastKey()
          : startAfter;

      // If shallow is true, only list immediate children
      // delimited by OZONE_URI_DELIMITER
      boolean shallow = listKeysShallowEnabled
          && OZONE_URI_DELIMITER.equals(delimiter);

      bucket = getBucket(bucketName);
      ozoneKeyIterator = bucket.listKeys(prefix, prevKey, shallow);

    } catch (OMException ex) {
      AUDIT.logReadFailure(
          buildAuditMessageForFailure(s3GAction, getAuditParameters(), ex));
      getMetrics().updateGetBucketFailureStats(startNanos);
      if (isAccessDenied(ex)) {
        throw newError(S3ErrorTable.ACCESS_DENIED, bucketName, ex);
      } else if (ex.getResult() == ResultCodes.FILE_NOT_FOUND) {
        // File not found, continue and send normal response with 0 keyCount
        LOG.debug("Key Not found prefix: {}", prefix);
      } else {
        throw ex;
      }
    } catch (Exception ex) {
      getMetrics().updateGetBucketFailureStats(startNanos);
      AUDIT.logReadFailure(
          buildAuditMessageForFailure(s3GAction, getAuditParameters(), ex));
      throw ex;
    }

    // The valid encodingType Values is "url"
    if (encodingType != null && !encodingType.equals(ENCODING_TYPE)) {
      throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT, encodingType);
    }

    // If you specify the encoding-type request parameter,should return
    // encoded key name values in the following response elements:
    //   Delimiter, Prefix, Key, and StartAfter.
    //
    // For detail refer:
    // https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html
    // #AmazonS3-ListObjectsV2-response-EncodingType
    //
    ListObjectResponse response = new ListObjectResponse();
    response.setDelimiter(
        EncodingTypeObject.createNullable(delimiter, encodingType));
    response.setName(bucketName);
    response.setPrefix(EncodingTypeObject.createNullable(prefix, encodingType));
    response.setMarker(marker == null ? "" : marker);
    response.setMaxKeys(maxKeys);
    response.setEncodingType(encodingType);
    response.setTruncated(false);
    response.setContinueToken(continueToken);
    response.setStartAfter(
        EncodingTypeObject.createNullable(startAfter, encodingType));

    String prevDir = null;
    if (continueToken != null) {
      prevDir = decodedToken.getLastDir();
    }
    String lastKey = null;
    int count = 0;
    while (ozoneKeyIterator != null && ozoneKeyIterator.hasNext()) {
      OzoneKey next = ozoneKeyIterator.next();
      if (bucket != null && bucket.getBucketLayout().isFileSystemOptimized() &&
          StringUtils.isNotEmpty(prefix) &&
          !next.getName().startsWith(prefix)) {
        // prefix has delimiter but key don't have
        // example prefix: dir1/ key: dir123
        continue;
      }
      if (startAfter != null && count == 0 && Objects.equals(startAfter, next.getName())) {
        continue;
      }
      String relativeKeyName = next.getName().substring(prefix.length());

      int depth = StringUtils.countMatches(relativeKeyName, delimiter);
      if (!StringUtils.isEmpty(delimiter)) {
        if (depth > 0) {
          // means key has multiple delimiters in its value.
          // ex: dir/dir1/dir2, where delimiter is "/" and prefix is dir/
          String dirName = relativeKeyName.substring(0, relativeKeyName
              .indexOf(delimiter));
          if (!dirName.equals(prevDir)) {
            response.addPrefix(EncodingTypeObject.createNullable(
                prefix + dirName + delimiter, encodingType));
            prevDir = dirName;
            count++;
          }
        } else if (relativeKeyName.endsWith(delimiter)) {
          // means or key is same as prefix with delimiter at end and ends with
          // delimiter. ex: dir/, where prefix is dir and delimiter is /
          response.addPrefix(
              EncodingTypeObject.createNullable(relativeKeyName, encodingType));
          count++;
        } else {
          // means our key is matched with prefix if prefix is given and it
          // does not have any common prefix.
          addKey(response, next);
          count++;
        }
      } else {
        addKey(response, next);
        count++;
      }

      if (count == maxKeys) {
        lastKey = next.getName();
        break;
      }
    }

    response.setKeyCount(count);

    if (count < maxKeys) {
      response.setTruncated(false);
    } else if (ozoneKeyIterator.hasNext()) {
      response.setTruncated(true);
      ContinueToken nextToken = new ContinueToken(lastKey, prevDir);
      response.setNextToken(nextToken.encodeToString());
      // Set nextMarker to be lastKey. for the compatibility of aws api v1
      response.setNextMarker(lastKey);
    } else {
      response.setTruncated(false);
    }

    int keyCount =
        response.getCommonPrefixes().size() + response.getContents().size();
    long opLatencyNs =
        getMetrics().updateGetBucketSuccessStats(startNanos);
    getMetrics().incListKeyCount(keyCount);
    perf.appendCount(keyCount);
    perf.appendOpLatencyNanos(opLatencyNs);
    AUDIT.logReadSuccess(buildAuditMessageForSuccess(s3GAction,
        getAuditParameters(), perf));
    response.setKeyCount(keyCount);
    return Response.ok(response).build();
  }