001package com.box.sdk;
002
003import static com.box.sdk.BinaryBodyUtils.writeStream;
004
005import com.eclipsesource.json.Json;
006import com.eclipsesource.json.JsonArray;
007import com.eclipsesource.json.JsonObject;
008import java.io.OutputStream;
009import java.net.URL;
010import java.util.List;
011
012/**
013 * Provides methods to allow users to download multiple files and folders as a single zip file. Users can download
014 * up to either 32GB or 10,000 files in one batch (whichever limitation is hit first) as a single zip file.
015 */
016public class BoxZip {
017    /**
018     * Zip URL Template.
019     */
020    public static final URLTemplate ZIP_URL_TEMPLATE = new URLTemplate("zip_downloads");
021    private final BoxAPIConnection api;
022
023    /**
024     * Constructs a Zip to be used by everything.
025     *
026     * @param api the API connection to be used by the Zip.
027     */
028    public BoxZip(BoxAPIConnection api) {
029        this.api = api;
030    }
031
032    /**
033     * Creates a zip of multiple files and folders.
034     *
035     * @param name  the name of the zip file to be created
036     * @param items list of files or folders to be part of the created zip
037     * @return information about the created zip file
038     */
039    public BoxZipInfo create(String name, List<BoxZipItem> items) {
040        JsonArray itemsArray = new JsonArray();
041        for (BoxZipItem item : items) {
042            itemsArray.add(item.getJSONObject());
043        }
044        JsonObject requestJSON = new JsonObject();
045        requestJSON.add("items", itemsArray);
046        requestJSON.add("download_file_name", name);
047
048        URL url = ZIP_URL_TEMPLATE.build(this.getAPI().getBaseURL());
049        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
050        request.setBody(requestJSON.toString());
051        try (BoxJSONResponse response = request.send()) {
052            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
053            return new BoxZipInfo(responseJSON);
054        }
055    }
056
057    /**
058     * Creates a zip and downloads it to a given OutputStream.
059     *
060     * @param name   the name of the zip file to be created
061     * @param items  list of files or folders to be part of the created zip
062     * @param output the stream to where the zip file will be written.
063     * @return information about status of the download
064     */
065    public BoxZipDownloadStatus download(String name, List<BoxZipItem> items, OutputStream output) {
066        return this.download(name, items, output, null);
067    }
068
069    /**
070     * Creates a zip and downloads its contents its to a given OutputStream.
071     *
072     * @param name     the name of the zip file to be created
073     * @param items    list of files or folders to be part of the created zip
074     * @param output   the stream to where the zip file will be written.
075     * @param listener a listener for monitoring the download's progress.
076     * @return information about status of the download
077     */
078    public BoxZipDownloadStatus download(
079        String name, List<BoxZipItem> items, OutputStream output, ProgressListener listener
080    ) {
081        BoxZipInfo zipInfo = this.create(name, items);
082        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), zipInfo.getDownloadURL(), "GET");
083        BoxAPIResponse response = request.send();
084        writeStream(response, output, listener);
085        BoxJSONRequest statusRequest = new BoxJSONRequest(this.getAPI(), zipInfo.getStatusURL(), "GET");
086        try (BoxJSONResponse statusResponse = statusRequest.send()) {
087            JsonObject statusResponseJSON = Json.parse(statusResponse.getJSON()).asObject();
088            return new BoxZipDownloadStatus(statusResponseJSON);
089        }
090    }
091
092    /**
093     * Gets the API connection used by this resource.
094     *
095     * @return the API connection used by this resource.
096     */
097    public BoxAPIConnection getAPI() {
098        return this.api;
099    }
100}