001package com.box.sdk;
002
003import com.eclipsesource.json.JsonObject;
004import com.eclipsesource.json.JsonValue;
005import java.io.IOException;
006import java.io.InputStream;
007import java.io.OutputStream;
008import java.net.URL;
009import java.text.ParseException;
010import java.util.Date;
011
012/**
013 * Represents a particular version of a file on Box.
014 */
015@BoxResourceType("file_version")
016public class BoxFileVersion extends BoxResource {
017    /**
018     * Content URL Template.
019     */
020    public static final URLTemplate CONTENT_URL_TEMPLATE = new URLTemplate("files/%s/content?version=%s");
021    /**
022     * Version URL Template.
023     */
024    public static final URLTemplate VERSION_URL_TEMPLATE = new URLTemplate("files/%s/versions/%s");
025    private static final int BUFFER_SIZE = 8192;
026
027    private String fileID;
028
029    private String versionID;
030    private String sha1;
031    private String name;
032    private long size;
033    private String uploaderDisplayName;
034    private Date createdAt;
035    private Date modifiedAt;
036    private BoxUser.Info modifiedBy;
037    private Date trashedAt;
038    private BoxUser.Info trashedBy;
039    private Date restoredAt;
040    private BoxUser.Info restoredBy;
041    private Date purgedAt;
042    private BoxFileVersion fileVersion;
043
044    /**
045     * Constructs a BoxFileVersion from a JSON string.
046     *
047     * @param api    the API connection to be used by the file.
048     * @param json   the JSON encoded file version.
049     * @param fileID the ID of the file.
050     */
051    public BoxFileVersion(BoxAPIConnection api, String json, String fileID) {
052        this(api, JsonObject.readFrom(json), fileID);
053    }
054
055    BoxFileVersion(BoxAPIConnection api, JsonObject jsonObject, String fileID) {
056        super(api, jsonObject.get("id").asString());
057
058        this.fileID = fileID;
059        this.parseJSON(jsonObject);
060    }
061
062    /**
063     * Method used to update fields with values received from API.
064     *
065     * @param jsonObject JSON-encoded info about File Version object.
066     */
067    private void parseJSON(JsonObject jsonObject) {
068        for (JsonObject.Member member : jsonObject) {
069            JsonValue value = member.getValue();
070            if (value.isNull()) {
071                continue;
072            }
073
074            try {
075                String memberName = member.getName();
076                if (memberName.equals("id")) {
077                    this.versionID = value.asString();
078                } else if (memberName.equals("sha1")) {
079                    this.sha1 = value.asString();
080                } else if (memberName.equals("name")) {
081                    this.name = value.asString();
082                } else if (memberName.equals("size")) {
083                    this.size = Double.valueOf(value.toString()).longValue();
084                } else if (memberName.equals("uploader_display_name")) {
085                    this.uploaderDisplayName = value.asString();
086                } else if (memberName.equals("created_at")) {
087                    this.createdAt = BoxDateFormat.parse(value.asString());
088                } else if (memberName.equals("modified_at")) {
089                    this.modifiedAt = BoxDateFormat.parse(value.asString());
090                } else if (memberName.equals("trashed_at")) {
091                    this.trashedAt = BoxDateFormat.parse(value.asString());
092                } else if (memberName.equals("trashed_by")) {
093                    JsonObject userJSON = value.asObject();
094                    String userID = userJSON.get("id").asString();
095                    BoxUser user = new BoxUser(getAPI(), userID);
096                    this.trashedBy = user.new Info(userJSON);
097                } else if (memberName.equals("modified_by")) {
098                    JsonObject userJSON = value.asObject();
099                    String userID = userJSON.get("id").asString();
100                    BoxUser user = new BoxUser(getAPI(), userID);
101                    this.modifiedBy = user.new Info(userJSON);
102                } else if (memberName.equals("restored_at")) {
103                    this.restoredAt = BoxDateFormat.parse(value.asString());
104                } else if (memberName.equals("restored_by")) {
105                    JsonObject userJSON = value.asObject();
106                    String userID = userJSON.get("id").asString();
107                    BoxUser user = new BoxUser(getAPI(), userID);
108                    this.restoredBy = user.new Info(userJSON);
109                } else if (memberName.equals("purged_at")) {
110                    this.purgedAt = BoxDateFormat.parse(value.asString());
111                } else if (memberName.equals("file_version")) {
112                    JsonObject fileVersionJson = value.asObject();
113                    String fileVersionId = fileVersionJson.get("id").asString();
114                    this.fileVersion = new BoxFileVersion(getAPI(), fileVersionJson, fileVersionId);
115                }
116            } catch (ParseException e) {
117                assert false : "A ParseException indicates a bug in the SDK.";
118            }
119        }
120    }
121
122    /**
123     * @return the file id this file version belongs to.
124     */
125    public String getFileID() {
126        return this.fileID;
127    }
128
129    /**
130     * Used if no or wrong file id was set with constructor.
131     *
132     * @param fileID the file id this file version belongs to.
133     */
134    public void setFileID(String fileID) {
135        this.fileID = fileID;
136    }
137
138    /**
139     * Gets the version ID of this version of the file.
140     *
141     * @return the version ID of this version of the file.
142     */
143    public String getVersionID() {
144        return this.versionID;
145    }
146
147    /**
148     * Gets the SHA1 hash of this version of the file.
149     *
150     * @return the SHA1 hash of this version of the file.
151     */
152    public String getSha1() {
153        return this.sha1;
154    }
155
156    /**
157     * Gets the name of this version of the file.
158     *
159     * @return the name of this version of the file.
160     */
161    public String getName() {
162        return this.name;
163    }
164
165    /**
166     * Gets the size of this version of the file.
167     *
168     * @return the size of this version of the file.
169     */
170    public long getSize() {
171        return this.size;
172    }
173
174    /**
175     * Gets the time that this version of the file was created.
176     *
177     * @return the time that this version of the file was created.
178     */
179    public Date getCreatedAt() {
180        return this.createdAt;
181    }
182
183    /**
184     * Gets the user's name at the time of upload.
185     *
186     * @return the time user's name at the time of upload.
187     */
188    public String getUploaderDisplayName() {
189        return this.uploaderDisplayName;
190    }
191
192    /**
193     * Gets the time that this version of the file was modified.
194     *
195     * @return the time that this version of the file was modified.
196     */
197    public Date getModifiedAt() {
198        return this.modifiedAt;
199    }
200
201    /**
202     * Gets the time that this version of the file was deleted.
203     *
204     * @return the time that this version of the file was deleted.
205     */
206    public Date getTrashedAt() {
207        return this.trashedAt;
208    }
209
210    /**
211     * Gets information about the user who trashed this version of the file.
212     *
213     * @return info about the user who trashed this version of the file.
214     */
215    public BoxUser.Info getTrashedBy() {
216        return this.trashedBy;
217    }
218
219    /**
220     * Gets information about the user who last modified this version of the file.
221     *
222     * @return info about the user who last modified this version of the file.
223     */
224    public BoxUser.Info getModifiedBy() {
225        return this.modifiedBy;
226    }
227
228    /**
229     * Gets the time that this version of the file was restored.
230     *
231     * @return the time that this version of the file was restored.
232     */
233    public Date getRestoredAt() {
234        return this.restoredAt;
235    }
236
237    /**
238     * Gets information about the user who restored this version of the file.
239     *
240     * @return info about the user who restored this version of the file.
241     */
242    public BoxUser.Info getRestoredBy() {
243        return this.restoredBy;
244    }
245
246    /**
247     * Gets the time that this version of the file was purged.
248     *
249     * @return the time that this version of the file was purged.
250     */
251    public Date getPurgedAt() {
252        return this.purgedAt;
253    }
254
255    /**
256     * Gets the file version for file version under retention.
257     *
258     * @return the file version for file version under retention.
259     */
260    public BoxFileVersion getFileVersion() {
261        return this.fileVersion;
262    }
263
264    /**
265     * Deletes this version of the file.
266     */
267    public void delete() {
268        URL url = VERSION_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.fileID, this.getID());
269        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
270        BoxAPIResponse response = request.send();
271        response.disconnect();
272    }
273
274    /**
275     * Downloads this version of the file to a given OutputStream.
276     *
277     * @param output the stream to where the file will be written.
278     */
279    public void download(OutputStream output) {
280        this.download(output, null);
281    }
282
283    /**
284     * Downloads this version of the file to a given OutputStream while reporting the progress to a ProgressListener.
285     *
286     * @param output   the stream to where the file will be written.
287     * @param listener a listener for monitoring the download's progress.
288     */
289    public void download(OutputStream output, ProgressListener listener) {
290        URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.fileID, this.getID());
291        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
292        BoxAPIResponse response = request.send();
293        InputStream input = response.getBody(listener);
294
295        long totalRead = 0;
296        byte[] buffer = new byte[BUFFER_SIZE];
297        try {
298            int n = input.read(buffer);
299            totalRead += n;
300            while (n != -1) {
301                output.write(buffer, 0, n);
302                n = input.read(buffer);
303                totalRead += n;
304            }
305        } catch (IOException e) {
306            throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
307        }
308
309        response.disconnect();
310    }
311
312    /**
313     * Promotes this version of the file to be the latest version.
314     */
315    public void promote() {
316        URL url = VERSION_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.fileID, "current");
317
318        JsonObject jsonObject = new JsonObject();
319        jsonObject.add("type", "file_version");
320        jsonObject.add("id", this.getID());
321
322        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
323        request.setBody(jsonObject.toString());
324        BoxJSONResponse response = (BoxJSONResponse) request.send();
325        this.parseJSON(JsonObject.readFrom(response.getJSON()));
326    }
327}