001package com.box.sdk;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.OutputStream;
006import java.net.URL;
007import java.util.List;
008
009import com.eclipsesource.json.JsonArray;
010import com.eclipsesource.json.JsonObject;
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    /**
022     * Zip Download URL Template.
023     */
024    public static final URLTemplate ZIP_DOWNLOAD_URL_TEMPLATE = new URLTemplate("zip_downloads/%s/content");
025    private static final int BUFFER_SIZE = 8192;
026    private final BoxAPIConnection api;
027
028    /**
029     * Constructs a Zip to be used by everything.
030     *
031     * @param api the API connection to be used by the Zip.
032     */
033    public BoxZip(BoxAPIConnection api) {
034        this.api = api;
035    }
036
037    /**
038     * Creates a zip of multiple files and folders.
039     *
040     * @param name  the name of the zip file to be created
041     * @param items list of files or folders to be part of the created zip
042     * @return      information about the created zip file
043     */
044    public BoxZipInfo create(String name, List<BoxZipItem> items) {
045        JsonArray itemsArray = new JsonArray();
046        for (BoxZipItem item : items) {
047            itemsArray.add(item.getJSONObject());
048        }
049        JsonObject requestJSON = new JsonObject();
050        requestJSON.add("items", itemsArray);
051        requestJSON.add("download_file_name", name);
052
053        URL url = ZIP_URL_TEMPLATE.build(this.getAPI().getBaseURL());
054        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST");
055        request.setBody(requestJSON.toString());
056        BoxJSONResponse response = (BoxJSONResponse) request.send();
057        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
058
059        BoxZipInfo zipInfo = new BoxZipInfo(responseJSON);
060        return zipInfo;
061    }
062
063    /**
064     * Creates a zip and downloads it to a given OutputStream.
065     *
066     * @param name   the name of the zip file to be created
067     * @param items  list of files or folders to be part of the created zip
068     * @param output the stream to where the zip file will be written.
069     * @return       information about status of the download
070     */
071    public BoxZipDownloadStatus download(String name, List<BoxZipItem> items, OutputStream output) {
072        return this.download(name, items, output, null);
073    }
074
075    /**
076     * Creates a zip and downloads its contents its to a given OutputStream.
077     *
078     * @param name     the name of the zip file to be created
079     * @param items    list of files or folders to be part of the created zip
080     * @param output   the stream to where the zip file will be written.
081     * @param listener a listener for monitoring the download's progress.
082     * @return         information about status of the download
083     */
084    public BoxZipDownloadStatus download(String name, List<BoxZipItem> items, OutputStream output,
085                                         ProgressListener listener) {
086        BoxZipInfo zipInfo = this.create(name, items);
087        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), zipInfo.getDownloadURL(), "GET");
088        BoxAPIResponse response = request.send();
089        InputStream input = response.getBody(listener);
090
091        byte[] buffer = new byte[BUFFER_SIZE];
092        try {
093            int n = input.read(buffer);
094            while (n != -1) {
095                output.write(buffer, 0, n);
096                n = input.read(buffer);
097            }
098        } catch (IOException e) {
099            throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
100        } finally {
101            response.disconnect();
102        }
103        BoxAPIRequest statusRequest = new BoxAPIRequest(this.getAPI(), zipInfo.getStatusURL(), "GET");
104        BoxJSONResponse statusResponse = (BoxJSONResponse) statusRequest.send();
105        JsonObject statusResponseJSON = JsonObject.readFrom(statusResponse.getJSON());
106        BoxZipDownloadStatus downloadStatus = new BoxZipDownloadStatus(statusResponseJSON);
107        return downloadStatus;
108    }
109
110    /**
111     * Gets the API connection used by this resource.
112     *
113     * @return the API connection used by this resource.
114     */
115    public BoxAPIConnection getAPI() {
116        return this.api;
117    }
118}