<commit_before>/*
 * Copyright 2015 Bounce Storage, Inc. <<EMAIL>>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bouncestorage.swiftproxy.v1;

import static java.util.Objects.requireNonNull;

import static com.google.common.base.Throwables.propagate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import com.bouncestorage.swiftproxy.BlobStoreResource;
import com.bouncestorage.swiftproxy.BounceResourceConfig;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;

import org.glassfish.grizzly.http.server.Request;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.util.Strings2;

@Singleton
@Path("/v1/{account}")
public final class AccountResource extends BlobStoreResource {
    private static final Iterable<Character> skipPathEncoding = Lists.charactersOf("/:;=");

    @GET
    public Response getAccount(@NotNull @PathParam("account") String account,
                               @QueryParam("limit") Optional<Integer> limit,
                               @QueryParam("marker") Optional<String> marker,
                               @QueryParam("end_marker") Optional<String> endMarker,
                               @QueryParam("format") Optional<String> format,
                               @QueryParam("prefix") Optional<String> prefix,
                               @QueryParam("delimiter") Optional<String> delimiter,
                               @HeaderParam("X-Auth-Token") String authToken,
                               @HeaderParam("X-Newest") @DefaultValue("false") boolean newest,
                               @HeaderParam("Accept") Optional<String> accept) {
        delimiter.ifPresent(x -> logger.info("delimiter not supported yet"));

        List<ContainerEntry> entries = getBlobStore(authToken).get().list()
                .stream()
                .map(StorageMetadata::getName)
                .filter(name -> marker.map(m -> name.compareTo(m) > 0).orElse(true))
                .filter(name -> endMarker.map(m -> name.compareTo(m) < 0).orElse(true))
                .filter(name -> prefix.map(name::startsWith).orElse(true))
                .limit(limit.orElse(Integer.MAX_VALUE))
                .map(ContainerEntry::new)
                .collect(Collectors.toList());

        MediaType formatType;
        if (format.isPresent()) {
            formatType = BounceResourceConfig.getMediaType(format.get());
        } else if (accept.isPresent()) {
            formatType = MediaType.valueOf(accept.get());
        } else {
            formatType = MediaType.TEXT_PLAIN_TYPE;
        }

        Account root = new Account();
        root.name = account;
        root.container = entries;
        return output(root, entries, formatType)
                .header("X-Account-Container-Count", entries.size())
                .header("X-Account-Object-Count", -1)
                .header("X-Account-Bytes-Used", -1)
                .header("X-Timestamp", -1)
                .header("X-Trans-Id", -1)
                .header("Accept-Ranges", "bytes")
                .build();
    }

    @HEAD
    public Response headAccount(@NotNull @PathParam("account") String account,
                                @HeaderParam("X-Auth-Token") String authToken,
                                @HeaderParam("X-Newest") boolean newest) {
        return Response.noContent()
                .header("X-Account-Container-Count", -1)
                .header("X-Account-Object-Count", -1)
                .header("X-Account-Bytes-Used", -1)
                .header("X-Timestamp", -1)
                .header("X-Trans-Id", -1)
                .header("Accept-Ranges", "bytes")
                .build();
    }

    @DELETE
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    public BulkDeleteResult bulkDeleteDelete(@NotNull @PathParam("account") String account,
                                             @QueryParam("bulk-delete") String bulkDelete,<commit_msg>send total container count regarldless of request limit<commit_after>/*
 * Copyright 2015 Bounce Storage, Inc. <<EMAIL>>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bouncestorage.swiftproxy.v1;

import static java.util.Objects.requireNonNull;

import static com.google.common.base.Throwables.propagate;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import com.bouncestorage.swiftproxy.BlobStoreResource;
import com.bouncestorage.swiftproxy.BounceResourceConfig;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;

import org.glassfish.grizzly.http.server.Request;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.util.Strings2;

@Singleton
@Path("/v1/{account}")
public final class AccountResource extends BlobStoreResource {
    private static final Iterable<Character> skipPathEncoding = Lists.charactersOf("/:;=");

    @GET
    public Response getAccount(@NotNull @PathParam("account") String account,
                               @QueryParam("limit") Optional<Integer> limit,
                               @QueryParam("marker") Optional<String> marker,
                               @QueryParam("end_marker") Optional<String> endMarker,
                               @QueryParam("format") Optional<String> format,
                               @QueryParam("prefix") Optional<String> prefix,
                               @QueryParam("delimiter") Optional<String> delimiter,
                               @HeaderParam("X-Auth-Token") String authToken,
                               @HeaderParam("X-Newest") @DefaultValue("false") boolean newest,
                               @HeaderParam("Accept") Optional<String> accept) {
        delimiter.ifPresent(x -> logger.info("delimiter not supported yet"));

        ArrayList<ContainerEntry> entries = getBlobStore(authToken).get().list()
                .stream()
                .map(StorageMetadata::getName)
                .filter(name -> marker.map(m -> name.compareTo(m) > 0).orElse(true))
                .filter(name -> endMarker.map(m -> name.compareTo(m) < 0).orElse(true))
                .filter(name -> prefix.map(name::startsWith).orElse(true))
                .map(ContainerEntry::new)
                .collect(Collectors.toCollection(ArrayList::new));

        MediaType formatType;
        if (format.isPresent()) {
            formatType = BounceResourceConfig.getMediaType(format.get());
        } else if (accept.isPresent()) {
            formatType = MediaType.valueOf(accept.get());
        } else {
            formatType = MediaType.TEXT_PLAIN_TYPE;
        }

        long count = entries.size();
        limit.ifPresent((max) -> {
            if (entries.size() > max) {
                entries.subList(max, entries.size()).clear();
            }
        });

        Account root = new Account();
        root.name = account;
        root.container = entries;
        return output(root, entries, formatType)
                .header("X-Account-Container-Count", count)
                .header("X-Account-Object-Count", -1)
                .header("X-Account-Bytes-Used", -1)
                .header("X-Timestamp", -1)
                .header("X-Trans-Id", -1)
                .header("Accept-Ranges", "bytes")
                .build();
    }

    @HEAD
    public Response headAccount(@NotNull @PathParam("account") String account,
                                @HeaderParam("X-Auth-Token") String authToken,
                                @HeaderParam("X-Newest") boolean newest) {
        return Response.noContent()
                .header("X-Account-Container-Count", -1)
                .header("X-Account-Object-Count", -1)
                .header("X-Account-Bytes-Used", -1)
                .header("X-Timestamp", -1)
                .header("X-Trans-Id", -1)
                .header("Accept-Ranges", "bytes")
                .build();
    }

    @DELETE
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    public BulkDeleteResult bulkDeleteDelete(@NotNull @PathParam("account") String account,
                                             @QueryParam("bulk-delete") String bulkDelete,
{'fraction_non_alphanumeric': 0.11763694212744003, 'fraction_numerical': 0.0037836443374322814, 'mean_word_length': 2.610679913070475, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 16}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2769531', 'n_tokens_mistral': 3244, 'n_tokens_neox': 3129, 'n_words': 670}