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