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    private BoxFileVersion fileVersion;
044
045    /**
046     * Constructs a BoxFileVersion from a JSON string.
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     * @param jsonObject JSON-encoded info about File Version object.
065     */
066    private void parseJSON(JsonObject jsonObject) {
067        for (JsonObject.Member member : jsonObject) {
068            JsonValue value = member.getValue();
069            if (value.isNull()) {
070                continue;
071            }
072
073            try {
074                String memberName = member.getName();
075                if (memberName.equals("id")) {
076                    this.versionID = value.asString();
077                } else if (memberName.equals("sha1")) {
078                    this.sha1 = value.asString();
079                } else if (memberName.equals("name")) {
080                    this.name = value.asString();
081                } else if (memberName.equals("size")) {
082                    this.size = Double.valueOf(value.toString()).longValue();
083                } else if (memberName.equals("uploader_display_name")) {
084                    this.uploaderDisplayName = value.asString();
085                } else if (memberName.equals("created_at")) {
086                    this.createdAt = BoxDateFormat.parse(value.asString());
087                } else if (memberName.equals("modified_at")) {
088                    this.modifiedAt = BoxDateFormat.parse(value.asString());
089                } else if (memberName.equals("trashed_at")) {
090                    this.trashedAt = BoxDateFormat.parse(value.asString());
091                } else if (memberName.equals("trashed_by")) {
092                    JsonObject userJSON = value.asObject();
093                    String userID = userJSON.get("id").asString();
094                    BoxUser user = new BoxUser(getAPI(), userID);
095                    this.trashedBy = user.new Info(userJSON);
096                } else if (memberName.equals("modified_by")) {
097                    JsonObject userJSON = value.asObject();
098                    String userID = userJSON.get("id").asString();
099                    BoxUser user = new BoxUser(getAPI(), userID);
100                    this.modifiedBy = user.new Info(userJSON);
101                } else if (memberName.equals("restored_at")) {
102                    this.restoredAt = BoxDateFormat.parse(value.asString());
103                } else if (memberName.equals("restored_by")) {
104                    JsonObject userJSON = value.asObject();
105                    String userID = userJSON.get("id").asString();
106                    BoxUser user = new BoxUser(getAPI(), userID);
107                    this.restoredBy = user.new Info(userJSON);
108                } else if (memberName.equals("purged_at")) {
109                    this.purgedAt = BoxDateFormat.parse(value.asString());
110                } else if (memberName.equals("file_version")) {
111                    JsonObject fileVersionJson = value.asObject();
112                    String fileVersionId = fileVersionJson.get("id").asString();
113                    this.fileVersion = new BoxFileVersion(getAPI(), fileVersionJson, fileVersionId);
114                }
115            } catch (ParseException e) {
116                assert false : "A ParseException indicates a bug in the SDK.";
117            }
118        }
119    }
120
121    /**
122     * Used if no or wrong file id was set with constructor.
123     * @param fileID the file id this file version belongs to.
124     */
125    public void setFileID(String fileID) {
126        this.fileID = fileID;
127    }
128
129    /**
130     * @return the file id this file version belongs to.
131     */
132    public String getFileID() {
133        return this.fileID;
134    }
135
136    /**
137     * Gets the version ID of this version of the file.
138     * @return the version ID of this version of the file.
139     */
140    public String getVersionID() {
141        return this.versionID;
142    }
143
144    /**
145     * Gets the SHA1 hash of this version of the file.
146     * @return the SHA1 hash of this version of the file.
147     */
148    public String getSha1() {
149        return this.sha1;
150    }
151
152    /**
153     * Gets the name of this version of the file.
154     * @return the name of this version of the file.
155     */
156    public String getName() {
157        return this.name;
158    }
159
160    /**
161     * Gets the size of this version of the file.
162     * @return the size of this version of the file.
163     */
164    public long getSize() {
165        return this.size;
166    }
167
168    /**
169     * Gets the time that this version of the file was created.
170     * @return the time that this version of the file was created.
171     */
172    public Date getCreatedAt() {
173        return this.createdAt;
174    }
175
176    /**
177     * Gets the user's name at the time of upload.
178     * @return the time user's name at the time of upload.
179     */
180    public String getUploaderDisplayName() {
181        return this.uploaderDisplayName;
182    }
183
184    /**
185     * Gets the time that this version of the file was modified.
186     * @return the time that this version of the file was modified.
187     */
188    public Date getModifiedAt() {
189        return this.modifiedAt;
190    }
191
192    /**
193     * Gets the time that this version of the file was deleted.
194     * @return the time that this version of the file was deleted.
195     */
196    public Date getTrashedAt() {
197        return this.trashedAt;
198    }
199
200    /**
201     * Gets information about the user who trashed this version of the file.
202     * @return info about the user who trashed this version of the file.
203     */
204    public BoxUser.Info getTrashedBy() {
205        return this.trashedBy;
206    }
207
208    /**
209     * Gets information about the user who last modified this version of the file.
210     * @return info about the user who last modified this version of the file.
211     */
212    public BoxUser.Info getModifiedBy() {
213        return this.modifiedBy;
214    }
215
216    /**
217     * Gets the time that this version of the file was restored.
218     * @return the time that this version of the file was restored.
219     */
220    public Date getRestoredAt() {
221        return this.restoredAt;
222    }
223
224    /**
225     * Gets information about the user who restored this version of the file.
226     * @return info about the user who restored this version of the file.
227     */
228    public BoxUser.Info getRestoredBy() {
229        return this.restoredBy;
230    }
231
232    /**
233     * Gets the time that this version of the file was purged.
234     * @return the time that this version of the file was purged.
235     */
236    public Date getPurgedAt() {
237        return this.purgedAt;
238    }
239
240    /**
241     * Gets the file version for file version under retention.
242     * @return the file version for file version under retention.
243     */
244    public BoxFileVersion getFileVersion() {
245        return this.fileVersion;
246    }
247
248    /**
249     * Deletes this version of the file.
250     */
251    public void delete() {
252        URL url = VERSION_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.fileID, this.getID());
253        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
254        BoxAPIResponse response = request.send();
255        response.disconnect();
256    }
257
258    /**
259     * Downloads this version of the file to a given OutputStream.
260     * @param output the stream to where the file will be written.
261     */
262    public void download(OutputStream output) {
263        this.download(output, null);
264    }
265
266    /**
267     * Downloads this version of the file to a given OutputStream while reporting the progress to a ProgressListener.
268     * @param output   the stream to where the file will be written.
269     * @param listener a listener for monitoring the download's progress.
270     */
271    public void download(OutputStream output, ProgressListener listener) {
272        URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.fileID, this.getID());
273        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
274        BoxAPIResponse response = request.send();
275        InputStream input = response.getBody(listener);
276
277        long totalRead = 0;
278        byte[] buffer = new byte[BUFFER_SIZE];
279        try {
280            int n = input.read(buffer);
281            totalRead += n;
282            while (n != -1) {
283                output.write(buffer, 0, n);
284                n = input.read(buffer);
285                totalRead += n;
286            }
287        } catch (IOException e) {
288            throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
289        }
290
291        response.disconnect();
292    }
293
294    /**
295     * Promotes this version of the file to be the latest version.
296     */
297    public void promote() {
298        URL url = VERSION_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.fileID, "current");
299
300        JsonObject jsonObject = new JsonObject();
301        jsonObject.add("type", "file_version");
302        jsonObject.add("id", this.getID());
303
304        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
305        request.setBody(jsonObject.toString());
306        BoxJSONResponse response = (BoxJSONResponse) request.send();
307        this.parseJSON(JsonObject.readFrom(response.getJSON()));
308    }
309}