001package com.box.sdk; 002 003import java.io.ByteArrayOutputStream; 004import java.io.IOException; 005import java.io.InputStream; 006import java.io.OutputStream; 007import java.net.MalformedURLException; 008import java.net.URL; 009import java.util.ArrayList; 010import java.util.Arrays; 011import java.util.Collection; 012import java.util.Date; 013import java.util.EnumSet; 014import java.util.HashSet; 015import java.util.List; 016import java.util.Map; 017import java.util.Set; 018import java.util.concurrent.TimeUnit; 019 020import com.box.sdk.internal.utils.Parsers; 021import com.eclipsesource.json.JsonArray; 022import com.eclipsesource.json.JsonObject; 023import com.eclipsesource.json.JsonValue; 024 025 026/** 027 * Represents an individual file on Box. This class can be used to download a file's contents, upload new versions, and 028 * perform other common file operations (move, copy, delete, etc.). 029 * 030 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 031 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 032 * handling for errors related to the Box REST API, you should capture this exception explicitly. 033 */ 034@BoxResourceType("file") 035public class BoxFile extends BoxItem { 036 037 /** 038 * An array of all possible file fields that can be requested when calling {@link #getInfo()}. 039 */ 040 public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "sha1", "name", 041 "description", "size", "path_collection", "created_at", "modified_at", 042 "trashed_at", "purged_at", "content_created_at", "content_modified_at", 043 "created_by", "modified_by", "owned_by", "shared_link", "parent", 044 "item_status", "version_number", "comment_count", "permissions", "tags", 045 "lock", "extension", "is_package", "file_version", "collections", 046 "watermark_info", "metadata", "representations"}; 047 048 /** 049 * Used to specify what filetype to request for a file thumbnail. 050 */ 051 public enum ThumbnailFileType { 052 /** 053 * PNG image format. 054 */ 055 PNG, 056 057 /** 058 * JPG image format. 059 */ 060 JPG 061 } 062 063 /** 064 * File URL Template. 065 */ 066 public static final URLTemplate FILE_URL_TEMPLATE = new URLTemplate("files/%s"); 067 /** 068 * Content URL Template. 069 */ 070 public static final URLTemplate CONTENT_URL_TEMPLATE = new URLTemplate("files/%s/content"); 071 /** 072 * Versions URL Template. 073 */ 074 public static final URLTemplate VERSIONS_URL_TEMPLATE = new URLTemplate("files/%s/versions"); 075 /** 076 * Copy URL Template. 077 */ 078 public static final URLTemplate COPY_URL_TEMPLATE = new URLTemplate("files/%s/copy"); 079 /** 080 * Add Comment URL Template. 081 */ 082 public static final URLTemplate ADD_COMMENT_URL_TEMPLATE = new URLTemplate("comments"); 083 /** 084 * Get Comments URL Template. 085 */ 086 public static final URLTemplate GET_COMMENTS_URL_TEMPLATE = new URLTemplate("files/%s/comments"); 087 /** 088 * Metadata URL Template. 089 */ 090 public static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("files/%s/metadata/%s/%s"); 091 /** 092 * Add Task URL Template. 093 */ 094 public static final URLTemplate ADD_TASK_URL_TEMPLATE = new URLTemplate("tasks"); 095 /** 096 * Get Tasks URL Template. 097 */ 098 public static final URLTemplate GET_TASKS_URL_TEMPLATE = new URLTemplate("files/%s/tasks"); 099 /** 100 * Get Thumbnail PNG Template. 101 */ 102 public static final URLTemplate GET_THUMBNAIL_PNG_TEMPLATE = new URLTemplate("files/%s/thumbnail.png"); 103 /** 104 * Get Thumbnail JPG Template. 105 */ 106 public static final URLTemplate GET_THUMBNAIL_JPG_TEMPLATE = new URLTemplate("files/%s/thumbnail.jpg"); 107 /** 108 * Upload Session URL Template. 109 */ 110 public static final URLTemplate UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/%s/upload_sessions"); 111 /** 112 * Upload Session Status URL Template. 113 */ 114 public static final URLTemplate UPLOAD_SESSION_STATUS_URL_TEMPLATE = new URLTemplate( 115 "files/upload_sessions/%s/status"); 116 /** 117 * Abort Upload Session URL Template. 118 */ 119 public static final URLTemplate ABORT_UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/upload_sessions/%s"); 120 /** 121 * Add Collaborations URL Template. 122 */ 123 public static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations"); 124 /** 125 * Get All File Collaborations URL Template. 126 */ 127 public static final URLTemplate GET_ALL_FILE_COLLABORATIONS_URL = new URLTemplate("files/%s/collaborations"); 128 private static final int BUFFER_SIZE = 8192; 129 private static final int GET_COLLABORATORS_PAGE_SIZE = 1000; 130 131 /** 132 * Constructs a BoxFile for a file with a given ID. 133 * 134 * @param api the API connection to be used by the file. 135 * @param id the ID of the file. 136 */ 137 public BoxFile(BoxAPIConnection api, String id) { 138 super(api, id); 139 } 140 141 /** 142 * {@inheritDoc} 143 */ 144 @Override 145 protected URL getItemURL() { 146 return FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 147 } 148 149 @Override 150 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 151 BoxSharedLink.Permissions permissions) { 152 153 BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions); 154 Info info = new Info(); 155 info.setSharedLink(sharedLink); 156 157 this.updateInfo(info); 158 return info.getSharedLink(); 159 } 160 161 /** 162 * Adds new {@link BoxWebHook} to this {@link BoxFile}. 163 * 164 * @param address {@link BoxWebHook.Info#getAddress()} 165 * @param triggers {@link BoxWebHook.Info#getTriggers()} 166 * @return created {@link BoxWebHook.Info} 167 */ 168 public BoxWebHook.Info addWebHook(URL address, BoxWebHook.Trigger... triggers) { 169 return BoxWebHook.create(this, address, triggers); 170 } 171 172 /** 173 * Adds a comment to this file. The message can contain @mentions by using the string @[userid:username] anywhere 174 * within the message, where userid and username are the ID and username of the person being mentioned. 175 * 176 * @param message the comment's message. 177 * @return information about the newly added comment. 178 * @see <a href="https://developers.box.com/docs/#comments-add-a-comment-to-an-item">the tagged_message field 179 * for including @mentions.</a> 180 */ 181 public BoxComment.Info addComment(String message) { 182 JsonObject itemJSON = new JsonObject(); 183 itemJSON.add("type", "file"); 184 itemJSON.add("id", this.getID()); 185 186 JsonObject requestJSON = new JsonObject(); 187 requestJSON.add("item", itemJSON); 188 if (BoxComment.messageContainsMention(message)) { 189 requestJSON.add("tagged_message", message); 190 } else { 191 requestJSON.add("message", message); 192 } 193 194 URL url = ADD_COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL()); 195 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 196 request.setBody(requestJSON.toString()); 197 BoxJSONResponse response = (BoxJSONResponse) request.send(); 198 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 199 200 BoxComment addedComment = new BoxComment(this.getAPI(), responseJSON.get("id").asString()); 201 return addedComment.new Info(responseJSON); 202 } 203 204 /** 205 * Adds a new task to this file. The task can have an optional message to include, and a due date. 206 * 207 * @param action the action the task assignee will be prompted to do. 208 * @param message an optional message to include with the task. 209 * @param dueAt the day at which this task is due. 210 * @return information about the newly added task. 211 */ 212 public BoxTask.Info addTask(BoxTask.Action action, String message, Date dueAt) { 213 JsonObject itemJSON = new JsonObject(); 214 itemJSON.add("type", "file"); 215 itemJSON.add("id", this.getID()); 216 217 JsonObject requestJSON = new JsonObject(); 218 requestJSON.add("item", itemJSON); 219 requestJSON.add("action", action.toJSONString()); 220 221 if (message != null && !message.isEmpty()) { 222 requestJSON.add("message", message); 223 } 224 225 if (dueAt != null) { 226 requestJSON.add("due_at", BoxDateFormat.format(dueAt)); 227 } 228 229 URL url = ADD_TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL()); 230 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 231 request.setBody(requestJSON.toString()); 232 BoxJSONResponse response = (BoxJSONResponse) request.send(); 233 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 234 235 BoxTask addedTask = new BoxTask(this.getAPI(), responseJSON.get("id").asString()); 236 return addedTask.new Info(responseJSON); 237 } 238 239 /** 240 * Gets an expiring URL for downloading a file directly from Box. This can be user, 241 * for example, for sending as a redirect to a browser to cause the browser 242 * to download the file directly from Box. 243 * 244 * @return the temporary download URL 245 */ 246 public URL getDownloadURL() { 247 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 248 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 249 request.setFollowRedirects(false); 250 251 BoxRedirectResponse response = (BoxRedirectResponse) request.send(); 252 253 return response.getRedirectURL(); 254 } 255 256 /** 257 * Downloads the contents of this file to a given OutputStream. 258 * 259 * @param output the stream to where the file will be written. 260 */ 261 public void download(OutputStream output) { 262 this.download(output, null); 263 } 264 265 /** 266 * Downloads the contents of this file to a given OutputStream while reporting the progress to a ProgressListener. 267 * 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.getID()); 273 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 274 BoxAPIResponse response = request.send(); 275 InputStream input = response.getBody(listener); 276 277 byte[] buffer = new byte[BUFFER_SIZE]; 278 try { 279 int n = input.read(buffer); 280 while (n != -1) { 281 output.write(buffer, 0, n); 282 n = input.read(buffer); 283 } 284 } catch (IOException e) { 285 throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); 286 } finally { 287 response.disconnect(); 288 } 289 } 290 291 /** 292 * Downloads a part of this file's contents, starting at specified byte offset. 293 * 294 * @param output the stream to where the file will be written. 295 * @param offset the byte offset at which to start the download. 296 */ 297 public void downloadRange(OutputStream output, long offset) { 298 this.downloadRange(output, offset, -1); 299 } 300 301 /** 302 * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd. 303 * 304 * @param output the stream to where the file will be written. 305 * @param rangeStart the byte offset at which to start the download. 306 * @param rangeEnd the byte offset at which to stop the download. 307 */ 308 public void downloadRange(OutputStream output, long rangeStart, long rangeEnd) { 309 this.downloadRange(output, rangeStart, rangeEnd, null); 310 } 311 312 /** 313 * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd, while reporting the 314 * progress to a ProgressListener. 315 * 316 * @param output the stream to where the file will be written. 317 * @param rangeStart the byte offset at which to start the download. 318 * @param rangeEnd the byte offset at which to stop the download. 319 * @param listener a listener for monitoring the download's progress. 320 */ 321 public void downloadRange(OutputStream output, long rangeStart, long rangeEnd, ProgressListener listener) { 322 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 323 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 324 if (rangeEnd > 0) { 325 request.addHeader("Range", String.format("bytes=%s-%s", Long.toString(rangeStart), 326 Long.toString(rangeEnd))); 327 } else { 328 request.addHeader("Range", String.format("bytes=%s-", Long.toString(rangeStart))); 329 } 330 331 BoxAPIResponse response = request.send(); 332 InputStream input = response.getBody(listener); 333 334 byte[] buffer = new byte[BUFFER_SIZE]; 335 try { 336 int n = input.read(buffer); 337 while (n != -1) { 338 output.write(buffer, 0, n); 339 n = input.read(buffer); 340 } 341 } catch (IOException e) { 342 throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); 343 } finally { 344 response.disconnect(); 345 } 346 } 347 348 @Override 349 public BoxFile.Info copy(BoxFolder destination) { 350 return this.copy(destination, null); 351 } 352 353 @Override 354 public BoxFile.Info copy(BoxFolder destination, String newName) { 355 URL url = COPY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 356 357 JsonObject parent = new JsonObject(); 358 parent.add("id", destination.getID()); 359 360 JsonObject copyInfo = new JsonObject(); 361 copyInfo.add("parent", parent); 362 if (newName != null) { 363 copyInfo.add("name", newName); 364 } 365 366 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 367 request.setBody(copyInfo.toString()); 368 BoxJSONResponse response = (BoxJSONResponse) request.send(); 369 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 370 BoxFile copiedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString()); 371 return copiedFile.new Info(responseJSON); 372 } 373 374 /** 375 * Deletes this file by moving it to the trash. 376 */ 377 public void delete() { 378 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 379 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 380 BoxAPIResponse response = request.send(); 381 response.disconnect(); 382 } 383 384 @Override 385 public BoxItem.Info move(BoxFolder destination) { 386 return this.move(destination, null); 387 } 388 389 @Override 390 public BoxItem.Info move(BoxFolder destination, String newName) { 391 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 392 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 393 394 JsonObject parent = new JsonObject(); 395 parent.add("id", destination.getID()); 396 397 JsonObject updateInfo = new JsonObject(); 398 updateInfo.add("parent", parent); 399 if (newName != null) { 400 updateInfo.add("name", newName); 401 } 402 403 request.setBody(updateInfo.toString()); 404 BoxJSONResponse response = (BoxJSONResponse) request.send(); 405 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 406 BoxFile movedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString()); 407 return movedFile.new Info(responseJSON); 408 } 409 410 /** 411 * Renames this file. 412 * 413 * @param newName the new name of the file. 414 */ 415 public void rename(String newName) { 416 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 417 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 418 419 JsonObject updateInfo = new JsonObject(); 420 updateInfo.add("name", newName); 421 422 request.setBody(updateInfo.toString()); 423 BoxAPIResponse response = request.send(); 424 response.disconnect(); 425 } 426 427 @Override 428 public BoxFile.Info getInfo() { 429 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 430 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 431 BoxJSONResponse response = (BoxJSONResponse) request.send(); 432 return new Info(response.getJSON()); 433 } 434 435 @Override 436 public BoxFile.Info getInfo(String... fields) { 437 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 438 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 439 440 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 441 BoxJSONResponse response = (BoxJSONResponse) request.send(); 442 return new Info(response.getJSON()); 443 } 444 445 /** 446 * Gets information about this item including a specified set of representations. 447 * @see <a href=https://developer.box.com/reference#section-x-rep-hints-header>X-Rep-Hints Header</a> 448 * 449 * @param representationHints hints for representations to be retrieved 450 * @param fields the fields to retrieve. 451 * @return info about this item containing only the specified fields, including representations. 452 */ 453 public BoxFile.Info getInfoWithRepresentations(String representationHints, String... fields) { 454 if (representationHints.matches(Representation.X_REP_HINTS_PATTERN)) { 455 //Since the user intends to get representations, add it to fields, even if user has missed it 456 Set<String> fieldsSet = new HashSet<String>(Arrays.asList(fields)); 457 fieldsSet.add("representations"); 458 String queryString = new QueryStringBuilder().appendParam("fields", 459 fieldsSet.toArray(new String[fieldsSet.size()])).toString(); 460 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 461 462 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 463 request.addHeader("X-Rep-Hints", representationHints); 464 BoxJSONResponse response = (BoxJSONResponse) request.send(); 465 return new Info(response.getJSON()); 466 } else { 467 throw new BoxAPIException("Represention hints is not valid." 468 + " Refer documention on how to construct X-Rep-Hints Header"); 469 } 470 } 471 472 /** 473 * Updates the information about this file with any info fields that have been modified locally. 474 * 475 * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following 476 * code won't update any information (or even send a network request) since none of the info's fields were 477 * changed:</p> 478 * 479 * <pre>BoxFile file = new File(api, id); 480 * BoxFile.Info info = file.getInfo(); 481 * file.updateInfo(info);</pre> 482 * 483 * @param info the updated info. 484 */ 485 public void updateInfo(BoxFile.Info info) { 486 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 487 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 488 request.setBody(info.getPendingChanges()); 489 BoxJSONResponse response = (BoxJSONResponse) request.send(); 490 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 491 info.update(jsonObject); 492 } 493 494 /** 495 * Gets any previous versions of this file. Note that only users with premium accounts will be able to retrieve 496 * previous versions of their files. 497 * 498 * @return a list of previous file versions. 499 */ 500 public Collection<BoxFileVersion> getVersions() { 501 URL url = VERSIONS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 502 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 503 BoxJSONResponse response = (BoxJSONResponse) request.send(); 504 505 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 506 JsonArray entries = jsonObject.get("entries").asArray(); 507 Collection<BoxFileVersion> versions = new ArrayList<BoxFileVersion>(); 508 for (JsonValue entry : entries) { 509 versions.add(new BoxFileVersion(this.getAPI(), entry.asObject(), this.getID())); 510 } 511 512 return versions; 513 } 514 515 /** 516 * Checks if the file can be successfully uploaded by using the preflight check. 517 * 518 * @param name the name to give the uploaded file or null to use existing name. 519 * @param fileSize the size of the file used for account capacity calculations. 520 * @param parentID the ID of the parent folder that the new version is being uploaded to. 521 */ 522 public void canUploadVersion(String name, long fileSize, String parentID) { 523 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 524 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 525 526 JsonObject parent = new JsonObject(); 527 parent.add("id", parentID); 528 529 JsonObject preflightInfo = new JsonObject(); 530 preflightInfo.add("parent", parent); 531 if (name != null) { 532 preflightInfo.add("name", name); 533 } 534 535 preflightInfo.add("size", fileSize); 536 537 request.setBody(preflightInfo.toString()); 538 BoxAPIResponse response = request.send(); 539 response.disconnect(); 540 } 541 542 /** 543 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 544 * will be able to view and recover previous versions of the file. 545 * 546 * @param fileContent a stream containing the new file contents. 547 * @deprecated use uploadNewVersion() instead. 548 */ 549 @Deprecated 550 public void uploadVersion(InputStream fileContent) { 551 this.uploadVersion(fileContent, null); 552 } 553 554 /** 555 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 556 * will be able to view and recover previous versions of the file. 557 * 558 * @param fileContent a stream containing the new file contents. 559 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 560 * @deprecated use uploadNewVersion() instead. 561 */ 562 @Deprecated 563 public void uploadVersion(InputStream fileContent, String fileContentSHA1) { 564 this.uploadVersion(fileContent, fileContentSHA1, null); 565 } 566 567 /** 568 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 569 * will be able to view and recover previous versions of the file. 570 * 571 * @param fileContent a stream containing the new file contents. 572 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 573 * @param modified the date that the new version was modified. 574 * @deprecated use uploadNewVersion() instead. 575 */ 576 @Deprecated 577 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 578 this.uploadVersion(fileContent, fileContentSHA1, modified, 0, null); 579 } 580 581 /** 582 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 583 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 584 * of the file. 585 * 586 * @param fileContent a stream containing the new file contents. 587 * @param modified the date that the new version was modified. 588 * @param fileSize the size of the file used for determining the progress of the upload. 589 * @param listener a listener for monitoring the upload's progress. 590 * @deprecated use uploadNewVersion() instead. 591 */ 592 @Deprecated 593 public void uploadVersion(InputStream fileContent, Date modified, long fileSize, ProgressListener listener) { 594 this.uploadVersion(fileContent, null, modified, fileSize, listener); 595 } 596 597 /** 598 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 599 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 600 * of the file. 601 * 602 * @param fileContent a stream containing the new file contents. 603 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 604 * @param modified the date that the new version was modified. 605 * @param fileSize the size of the file used for determining the progress of the upload. 606 * @param listener a listener for monitoring the upload's progress. 607 * @deprecated use uploadNewVersion() instead. 608 */ 609 @Deprecated 610 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 611 ProgressListener listener) { 612 this.uploadNewVersion(fileContent, fileContentSHA1, modified, fileSize, listener); 613 return; 614 } 615 616 /** 617 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 618 * will be able to view and recover previous versions of the file. 619 * 620 * @param fileContent a stream containing the new file contents. 621 * @return the uploaded file version. 622 */ 623 public BoxFile.Info uploadNewVersion(InputStream fileContent) { 624 return this.uploadNewVersion(fileContent, null); 625 } 626 627 /** 628 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 629 * will be able to view and recover previous versions of the file. 630 * 631 * @param fileContent a stream containing the new file contents. 632 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 633 * @return the uploaded file version. 634 */ 635 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1) { 636 return this.uploadNewVersion(fileContent, fileContentSHA1, null); 637 } 638 639 /** 640 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 641 * will be able to view and recover previous versions of the file. 642 * 643 * @param fileContent a stream containing the new file contents. 644 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 645 * @param modified the date that the new version was modified. 646 * @return the uploaded file version. 647 */ 648 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 649 return this.uploadNewVersion(fileContent, fileContentSHA1, modified, 0, null); 650 } 651 652 /** 653 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 654 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 655 * of the file. 656 * 657 * @param fileContent a stream containing the new file contents. 658 * @param modified the date that the new version was modified. 659 * @param fileSize the size of the file used for determining the progress of the upload. 660 * @param listener a listener for monitoring the upload's progress. 661 * @return the uploaded file version. 662 */ 663 public BoxFile.Info uploadNewVersion(InputStream fileContent, Date modified, long fileSize, 664 ProgressListener listener) { 665 return this.uploadNewVersion(fileContent, null, modified, fileSize, listener); 666 } 667 668 /** 669 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 670 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 671 * of the file. 672 * 673 * @param fileContent a stream containing the new file contents. 674 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 675 * @param modified the date that the new version was modified. 676 * @param fileSize the size of the file used for determining the progress of the upload. 677 * @param listener a listener for monitoring the upload's progress. 678 * @return the uploaded file version. 679 */ 680 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 681 ProgressListener listener) { 682 URL uploadURL = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 683 BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL); 684 685 if (fileSize > 0) { 686 request.setFile(fileContent, "", fileSize); 687 } else { 688 request.setFile(fileContent, ""); 689 } 690 691 if (fileContentSHA1 != null) { 692 request.setContentSHA1(fileContentSHA1); 693 } 694 695 if (modified != null) { 696 request.putField("content_modified_at", modified); 697 } 698 699 BoxJSONResponse response; 700 if (listener == null) { 701 response = (BoxJSONResponse) request.send(); 702 } else { 703 response = (BoxJSONResponse) request.send(listener); 704 } 705 706 return new BoxFile.Info(response.getJSON()); 707 } 708 709 /** 710 * Gets an expiring URL for creating an embedded preview session. The URL will expire after 60 seconds and the 711 * preview session will expire after 60 minutes. 712 * 713 * @return the expiring preview link 714 */ 715 public URL getPreviewLink() { 716 BoxFile.Info info = this.getInfo("expiring_embed_link"); 717 718 return info.getPreviewLink(); 719 } 720 721 722 /** 723 * Retrieves a thumbnail, or smaller image representation, of this file. Sizes of 32x32, 64x64, 128x128, 724 * and 256x256 can be returned in the .png format and sizes of 32x32, 94x94, 160x160, and 320x320 can be returned 725 * in the .jpg format. 726 * 727 * @param fileType either PNG of JPG 728 * @param minWidth minimum width 729 * @param minHeight minimum height 730 * @param maxWidth maximum width 731 * @param maxHeight maximum height 732 * @return the byte array of the thumbnail image 733 */ 734 public byte[] getThumbnail(ThumbnailFileType fileType, int minWidth, int minHeight, int maxWidth, int maxHeight) { 735 QueryStringBuilder builder = new QueryStringBuilder(); 736 builder.appendParam("min_width", minWidth); 737 builder.appendParam("min_height", minHeight); 738 builder.appendParam("max_width", maxWidth); 739 builder.appendParam("max_height", maxHeight); 740 741 URLTemplate template; 742 if (fileType == ThumbnailFileType.PNG) { 743 template = GET_THUMBNAIL_PNG_TEMPLATE; 744 } else if (fileType == ThumbnailFileType.JPG) { 745 template = GET_THUMBNAIL_JPG_TEMPLATE; 746 } else { 747 throw new BoxAPIException("Unsupported thumbnail file type"); 748 } 749 URL url = template.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID()); 750 751 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 752 BoxAPIResponse response = request.send(); 753 754 ByteArrayOutputStream thumbOut = new ByteArrayOutputStream(); 755 InputStream body = response.getBody(); 756 byte[] buffer = new byte[BUFFER_SIZE]; 757 try { 758 int n = body.read(buffer); 759 while (n != -1) { 760 thumbOut.write(buffer, 0, n); 761 n = body.read(buffer); 762 } 763 } catch (IOException e) { 764 throw new BoxAPIException("Error reading thumbnail bytes from response body", e); 765 } finally { 766 response.disconnect(); 767 } 768 769 return thumbOut.toByteArray(); 770 } 771 772 /** 773 * Gets a list of any comments on this file. 774 * 775 * @return a list of comments on this file. 776 */ 777 public List<BoxComment.Info> getComments() { 778 URL url = GET_COMMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 779 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 780 BoxJSONResponse response = (BoxJSONResponse) request.send(); 781 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 782 783 int totalCount = responseJSON.get("total_count").asInt(); 784 List<BoxComment.Info> comments = new ArrayList<BoxComment.Info>(totalCount); 785 JsonArray entries = responseJSON.get("entries").asArray(); 786 for (JsonValue value : entries) { 787 JsonObject commentJSON = value.asObject(); 788 BoxComment comment = new BoxComment(this.getAPI(), commentJSON.get("id").asString()); 789 BoxComment.Info info = comment.new Info(commentJSON); 790 comments.add(info); 791 } 792 793 return comments; 794 } 795 796 /** 797 * Gets a list of any tasks on this file. 798 * 799 * @return a list of tasks on this file. 800 */ 801 public List<BoxTask.Info> getTasks() { 802 URL url = GET_TASKS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 803 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 804 BoxJSONResponse response = (BoxJSONResponse) request.send(); 805 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 806 807 int totalCount = responseJSON.get("total_count").asInt(); 808 List<BoxTask.Info> tasks = new ArrayList<BoxTask.Info>(totalCount); 809 JsonArray entries = responseJSON.get("entries").asArray(); 810 for (JsonValue value : entries) { 811 JsonObject taskJSON = value.asObject(); 812 BoxTask task = new BoxTask(this.getAPI(), taskJSON.get("id").asString()); 813 BoxTask.Info info = task.new Info(taskJSON); 814 tasks.add(info); 815 } 816 817 return tasks; 818 } 819 820 /** 821 * Creates metadata on this file in the global properties template. 822 * 823 * @param metadata The new metadata values. 824 * @return the metadata returned from the server. 825 */ 826 public Metadata createMetadata(Metadata metadata) { 827 return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata); 828 } 829 830 /** 831 * Creates metadata on this file in the specified template type. 832 * 833 * @param typeName the metadata template type name. 834 * @param metadata the new metadata values. 835 * @return the metadata returned from the server. 836 */ 837 public Metadata createMetadata(String typeName, Metadata metadata) { 838 String scope = Metadata.scopeBasedOnType(typeName); 839 return this.createMetadata(typeName, scope, metadata); 840 } 841 842 /** 843 * Creates metadata on this file in the specified template type. 844 * 845 * @param typeName the metadata template type name. 846 * @param scope the metadata scope (global or enterprise). 847 * @param metadata the new metadata values. 848 * @return the metadata returned from the server. 849 */ 850 public Metadata createMetadata(String typeName, String scope, Metadata metadata) { 851 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 852 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST"); 853 request.addHeader("Content-Type", "application/json"); 854 request.setBody(metadata.toString()); 855 BoxJSONResponse response = (BoxJSONResponse) request.send(); 856 return new Metadata(JsonObject.readFrom(response.getJSON())); 857 } 858 859 /** 860 * Locks a file. 861 * 862 * @return the lock returned from the server. 863 */ 864 public BoxLock lock() { 865 return this.lock(null, false); 866 } 867 868 /** 869 * Locks a file. 870 * 871 * @param isDownloadPrevented is downloading of file prevented when locked. 872 * @return the lock returned from the server. 873 */ 874 public BoxLock lock(boolean isDownloadPrevented) { 875 return this.lock(null, isDownloadPrevented); 876 } 877 878 /** 879 * Locks a file. 880 * 881 * @param expiresAt expiration date of the lock. 882 * @return the lock returned from the server. 883 */ 884 public BoxLock lock(Date expiresAt) { 885 return this.lock(expiresAt, false); 886 } 887 888 /** 889 * Locks a file. 890 * 891 * @param expiresAt expiration date of the lock. 892 * @param isDownloadPrevented is downloading of file prevented when locked. 893 * @return the lock returned from the server. 894 */ 895 public BoxLock lock(Date expiresAt, boolean isDownloadPrevented) { 896 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 897 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 898 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 899 900 JsonObject lockConfig = new JsonObject(); 901 lockConfig.add("type", "lock"); 902 if (expiresAt != null) { 903 lockConfig.add("expires_at", BoxDateFormat.format(expiresAt)); 904 } 905 lockConfig.add("is_download_prevented", isDownloadPrevented); 906 907 JsonObject requestJSON = new JsonObject(); 908 requestJSON.add("lock", lockConfig); 909 request.setBody(requestJSON.toString()); 910 911 BoxJSONResponse response = (BoxJSONResponse) request.send(); 912 913 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 914 JsonValue lockValue = responseJSON.get("lock"); 915 JsonObject lockJSON = JsonObject.readFrom(lockValue.toString()); 916 917 return new BoxLock(lockJSON, this.getAPI()); 918 } 919 920 /** 921 * Unlocks a file. 922 */ 923 public void unlock() { 924 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 925 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 926 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 927 928 JsonObject lockObject = new JsonObject(); 929 lockObject.add("lock", JsonObject.NULL); 930 931 request.setBody(lockObject.toString()); 932 request.send(); 933 } 934 935 /** 936 * Used to retrieve all metadata associated with the file. 937 * 938 * @param fields the optional fields to retrieve. 939 * @return An iterable of metadata instances associated with the file. 940 */ 941 public Iterable<Metadata> getAllMetadata(String... fields) { 942 return Metadata.getAllMetadata(this, fields); 943 } 944 945 /** 946 * Gets the file properties metadata. 947 * 948 * @return the metadata returned from the server. 949 */ 950 public Metadata getMetadata() { 951 return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE); 952 } 953 954 /** 955 * Gets the file metadata of specified template type. 956 * 957 * @param typeName the metadata template type name. 958 * @return the metadata returned from the server. 959 */ 960 public Metadata getMetadata(String typeName) { 961 String scope = Metadata.scopeBasedOnType(typeName); 962 return this.getMetadata(typeName, scope); 963 } 964 965 /** 966 * Gets the file metadata of specified template type. 967 * 968 * @param typeName the metadata template type name. 969 * @param scope the metadata scope (global or enterprise). 970 * @return the metadata returned from the server. 971 */ 972 public Metadata getMetadata(String typeName, String scope) { 973 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 974 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 975 BoxJSONResponse response = (BoxJSONResponse) request.send(); 976 return new Metadata(JsonObject.readFrom(response.getJSON())); 977 } 978 979 /** 980 * Updates the file metadata. 981 * 982 * @param metadata the new metadata values. 983 * @return the metadata returned from the server. 984 */ 985 public Metadata updateMetadata(Metadata metadata) { 986 String scope; 987 if (metadata.getScope().equals(Metadata.GLOBAL_METADATA_SCOPE)) { 988 scope = Metadata.GLOBAL_METADATA_SCOPE; 989 } else { 990 scope = Metadata.ENTERPRISE_METADATA_SCOPE; 991 } 992 993 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), 994 scope, metadata.getTemplateName()); 995 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 996 request.addHeader("Content-Type", "application/json-patch+json"); 997 request.setBody(metadata.getPatch()); 998 BoxJSONResponse response = (BoxJSONResponse) request.send(); 999 return new Metadata(JsonObject.readFrom(response.getJSON())); 1000 } 1001 1002 /** 1003 * Deletes the file properties metadata. 1004 */ 1005 public void deleteMetadata() { 1006 this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE); 1007 } 1008 1009 /** 1010 * Deletes the file metadata of specified template type. 1011 * 1012 * @param typeName the metadata template type name. 1013 */ 1014 public void deleteMetadata(String typeName) { 1015 String scope = Metadata.scopeBasedOnType(typeName); 1016 this.deleteMetadata(typeName, scope); 1017 } 1018 1019 /** 1020 * Deletes the file metadata of specified template type. 1021 * 1022 * @param typeName the metadata template type name. 1023 * @param scope the metadata scope (global or enterprise). 1024 */ 1025 public void deleteMetadata(String typeName, String scope) { 1026 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1027 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 1028 request.send(); 1029 } 1030 1031 /** 1032 * Used to retrieve the watermark for the file. 1033 * If the file does not have a watermark applied to it, a 404 Not Found will be returned by API. 1034 * 1035 * @param fields the fields to retrieve. 1036 * @return the watermark associated with the file. 1037 */ 1038 public BoxWatermark getWatermark(String... fields) { 1039 return this.getWatermark(FILE_URL_TEMPLATE, fields); 1040 } 1041 1042 /** 1043 * Used to apply or update the watermark for the file. 1044 * 1045 * @return the watermark associated with the file. 1046 */ 1047 public BoxWatermark applyWatermark() { 1048 return this.applyWatermark(FILE_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT); 1049 } 1050 1051 /** 1052 * Removes a watermark from the file. 1053 * If the file did not have a watermark applied to it, a 404 Not Found will be returned by API. 1054 */ 1055 public void removeWatermark() { 1056 this.removeWatermark(FILE_URL_TEMPLATE); 1057 } 1058 1059 /** 1060 * {@inheritDoc} 1061 */ 1062 @Override 1063 public BoxFile.Info setCollections(BoxCollection... collections) { 1064 JsonArray jsonArray = new JsonArray(); 1065 for (BoxCollection collection : collections) { 1066 JsonObject collectionJSON = new JsonObject(); 1067 collectionJSON.add("id", collection.getID()); 1068 jsonArray.add(collectionJSON); 1069 } 1070 JsonObject infoJSON = new JsonObject(); 1071 infoJSON.add("collections", jsonArray); 1072 1073 String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString(); 1074 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 1075 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 1076 request.setBody(infoJSON.toString()); 1077 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1078 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1079 return new Info(jsonObject); 1080 } 1081 1082 /** 1083 * Creates an upload session to create a new version of a file in chunks. 1084 * This will first verify that the version can be created and then open a session for uploading pieces of the file. 1085 * @param fileSize the size of the file that will be uploaded. 1086 * @return the created upload session instance. 1087 */ 1088 public BoxFileUploadSession.Info createUploadSession(long fileSize) { 1089 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1090 1091 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 1092 request.addHeader("Content-Type", "application/json"); 1093 1094 JsonObject body = new JsonObject(); 1095 body.add("file_size", fileSize); 1096 request.setBody(body.toString()); 1097 1098 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1099 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1100 1101 String sessionId = jsonObject.get("id").asString(); 1102 BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId); 1103 return session.new Info(jsonObject); 1104 } 1105 1106 /** 1107 * Creates a new version of a file. 1108 * @param inputStream the stream instance that contains the data. 1109 * @param fileSize the size of the file that will be uploaded. 1110 * @return the created file instance. 1111 * @throws InterruptedException when a thread execution is interrupted. 1112 * @throws IOException when reading a stream throws exception. 1113 */ 1114 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize) 1115 throws InterruptedException, IOException { 1116 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1117 return new LargeFileUpload().upload(this.getAPI(), inputStream, url, fileSize); 1118 } 1119 1120 /** 1121 * Creates a new version of a file using specified number of parallel http connections. 1122 * @param inputStream the stream instance that contains the data. 1123 * @param fileSize the size of the file that will be uploaded. 1124 * @param nParallelConnections number of parallel http connections to use 1125 * @param timeOut time to wait before killing the job 1126 * @param unit time unit for the time wait value 1127 * @return the created file instance. 1128 * @throws InterruptedException when a thread execution is interrupted. 1129 * @throws IOException when reading a stream throws exception. 1130 */ 1131 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize, 1132 int nParallelConnections, long timeOut, TimeUnit unit) 1133 throws InterruptedException, IOException { 1134 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1135 return new LargeFileUpload(nParallelConnections, timeOut, unit) 1136 .upload(this.getAPI(), inputStream, url, fileSize); 1137 } 1138 1139 /** 1140 * Contains information about a BoxFile. 1141 */ 1142 public class Info extends BoxItem.Info { 1143 private String sha1; 1144 private String versionNumber; 1145 private long commentCount; 1146 private EnumSet<Permission> permissions; 1147 private String extension; 1148 private boolean isPackage; 1149 private BoxFileVersion version; 1150 private URL previewLink; 1151 private BoxLock lock; 1152 private boolean isWatermarked; 1153 private JsonObject metadata; 1154 private Map<String, Map<String, Metadata>> metadataMap; 1155 private List<Representation> representations; 1156 1157 /** 1158 * Constructs an empty Info object. 1159 */ 1160 public Info() { 1161 super(); 1162 } 1163 1164 /** 1165 * Constructs an Info object by parsing information from a JSON string. 1166 * 1167 * @param json the JSON string to parse. 1168 */ 1169 public Info(String json) { 1170 super(json); 1171 } 1172 1173 /** 1174 * Constructs an Info object using an already parsed JSON object. 1175 * 1176 * @param jsonObject the parsed JSON object. 1177 */ 1178 public Info(JsonObject jsonObject) { 1179 super(jsonObject); 1180 } 1181 1182 @Override 1183 public BoxFile getResource() { 1184 return BoxFile.this; 1185 } 1186 1187 /** 1188 * Gets the SHA1 hash of the file. 1189 * 1190 * @return the SHA1 hash of the file. 1191 */ 1192 public String getSha1() { 1193 return this.sha1; 1194 } 1195 1196 /** 1197 * Gets the lock of the file. 1198 * 1199 * @return the lock of the file. 1200 */ 1201 public BoxLock getLock() { 1202 return this.lock; 1203 } 1204 1205 /** 1206 * Gets the current version number of the file. 1207 * 1208 * @return the current version number of the file. 1209 */ 1210 public String getVersionNumber() { 1211 return this.versionNumber; 1212 } 1213 1214 /** 1215 * Gets the number of comments on the file. 1216 * 1217 * @return the number of comments on the file. 1218 */ 1219 public long getCommentCount() { 1220 return this.commentCount; 1221 } 1222 1223 /** 1224 * Gets the permissions that the current user has on the file. 1225 * 1226 * @return the permissions that the current user has on the file. 1227 */ 1228 public EnumSet<Permission> getPermissions() { 1229 return this.permissions; 1230 } 1231 1232 /** 1233 * Gets the extension suffix of the file, excluding the dot. 1234 * 1235 * @return the extension of the file. 1236 */ 1237 public String getExtension() { 1238 return this.extension; 1239 } 1240 1241 /** 1242 * Gets whether or not the file is an OSX package. 1243 * 1244 * @return true if the file is an OSX package; otherwise false. 1245 */ 1246 public boolean getIsPackage() { 1247 return this.isPackage; 1248 } 1249 1250 /** 1251 * Gets the current version details of the file. 1252 * 1253 * @return the current version details of the file. 1254 */ 1255 public BoxFileVersion getVersion() { 1256 return this.version; 1257 } 1258 1259 /** 1260 * Gets the current expiring preview link. 1261 * 1262 * @return the expiring preview link 1263 */ 1264 public URL getPreviewLink() { 1265 return this.previewLink; 1266 } 1267 1268 /** 1269 * Gets flag indicating whether this file is Watermarked. 1270 * 1271 * @return whether the file is watermarked or not 1272 */ 1273 public boolean getIsWatermarked() { 1274 return this.isWatermarked; 1275 } 1276 1277 /** 1278 * Gets the metadata on this file associated with a specified scope and template. 1279 * Makes an attempt to get metadata that was retrieved using getInfo(String ...) method. If no result is found 1280 * then makes an API call to get metadata 1281 * @param templateName the metadata template type name. 1282 * @param scope the scope of the template (usually "global" or "enterprise"). 1283 * @return the metadata returned from the server. 1284 */ 1285 public Metadata getMetadata(String templateName, String scope) { 1286 try { 1287 return this.metadataMap.get(scope).get(templateName); 1288 } catch (NullPointerException e) { 1289 return null; 1290 } 1291 } 1292 1293 /** 1294 * Get file's representations. 1295 * @return list of representations 1296 */ 1297 public List<Representation> getRepresentations() { 1298 return this.representations; 1299 } 1300 1301 @Override 1302 protected void parseJSONMember(JsonObject.Member member) { 1303 super.parseJSONMember(member); 1304 1305 String memberName = member.getName(); 1306 JsonValue value = member.getValue(); 1307 if (memberName.equals("sha1")) { 1308 this.sha1 = value.asString(); 1309 } else if (memberName.equals("version_number")) { 1310 this.versionNumber = value.asString(); 1311 } else if (memberName.equals("comment_count")) { 1312 this.commentCount = value.asLong(); 1313 } else if (memberName.equals("permissions")) { 1314 this.permissions = this.parsePermissions(value.asObject()); 1315 } else if (memberName.equals("extension")) { 1316 this.extension = value.asString(); 1317 } else if (memberName.equals("is_package")) { 1318 this.isPackage = value.asBoolean(); 1319 } else if (memberName.equals("file_version")) { 1320 this.version = this.parseFileVersion(value.asObject()); 1321 } else if (memberName.equals("expiring_embed_link")) { 1322 try { 1323 String urlString = member.getValue().asObject().get("url").asString(); 1324 this.previewLink = new URL(urlString); 1325 } catch (MalformedURLException e) { 1326 throw new BoxAPIException("Couldn't parse expiring_embed_link/url for file", e); 1327 } 1328 } else if (memberName.equals("lock")) { 1329 if (value.isNull()) { 1330 this.lock = null; 1331 } else { 1332 this.lock = new BoxLock(value.asObject(), BoxFile.this.getAPI()); 1333 } 1334 } else if (memberName.equals("watermark_info")) { 1335 JsonObject jsonObject = value.asObject(); 1336 this.isWatermarked = jsonObject.get("is_watermarked").asBoolean(); 1337 } else if (memberName.equals("metadata")) { 1338 JsonObject jsonObject = value.asObject(); 1339 this.metadataMap = Parsers.parseAndPopulateMetadataMap(jsonObject); 1340 } else if (memberName.equals("representations")) { 1341 JsonObject jsonObject = value.asObject(); 1342 this.representations = Parsers.parseRepresentations(jsonObject); 1343 } 1344 } 1345 1346 private EnumSet<Permission> parsePermissions(JsonObject jsonObject) { 1347 EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class); 1348 for (JsonObject.Member member : jsonObject) { 1349 JsonValue value = member.getValue(); 1350 if (value.isNull() || !value.asBoolean()) { 1351 continue; 1352 } 1353 1354 String memberName = member.getName(); 1355 if (memberName.equals("can_download")) { 1356 permissions.add(Permission.CAN_DOWNLOAD); 1357 } else if (memberName.equals("can_upload")) { 1358 permissions.add(Permission.CAN_UPLOAD); 1359 } else if (memberName.equals("can_rename")) { 1360 permissions.add(Permission.CAN_RENAME); 1361 } else if (memberName.equals("can_delete")) { 1362 permissions.add(Permission.CAN_DELETE); 1363 } else if (memberName.equals("can_share")) { 1364 permissions.add(Permission.CAN_SHARE); 1365 } else if (memberName.equals("can_set_share_access")) { 1366 permissions.add(Permission.CAN_SET_SHARE_ACCESS); 1367 } else if (memberName.equals("can_preview")) { 1368 permissions.add(Permission.CAN_PREVIEW); 1369 } else if (memberName.equals("can_comment")) { 1370 permissions.add(Permission.CAN_COMMENT); 1371 } 1372 } 1373 1374 return permissions; 1375 } 1376 1377 private BoxFileVersion parseFileVersion(JsonObject jsonObject) { 1378 return new BoxFileVersion(BoxFile.this.getAPI(), jsonObject, BoxFile.this.getID()); 1379 } 1380 } 1381 1382 /** 1383 * Enumerates the possible permissions that a user can have on a file. 1384 */ 1385 public enum Permission { 1386 /** 1387 * The user can download the file. 1388 */ 1389 CAN_DOWNLOAD("can_download"), 1390 1391 /** 1392 * The user can upload new versions of the file. 1393 */ 1394 CAN_UPLOAD("can_upload"), 1395 1396 /** 1397 * The user can rename the file. 1398 */ 1399 CAN_RENAME("can_rename"), 1400 1401 /** 1402 * The user can delete the file. 1403 */ 1404 CAN_DELETE("can_delete"), 1405 1406 /** 1407 * The user can share the file. 1408 */ 1409 CAN_SHARE("can_share"), 1410 1411 /** 1412 * The user can set the access level for shared links to the file. 1413 */ 1414 CAN_SET_SHARE_ACCESS("can_set_share_access"), 1415 1416 /** 1417 * The user can preview the file. 1418 */ 1419 CAN_PREVIEW("can_preview"), 1420 1421 /** 1422 * The user can comment on the file. 1423 */ 1424 CAN_COMMENT("can_comment"); 1425 1426 private final String jsonValue; 1427 1428 private Permission(String jsonValue) { 1429 this.jsonValue = jsonValue; 1430 } 1431 1432 static Permission fromJSONValue(String jsonValue) { 1433 return Permission.valueOf(jsonValue.toUpperCase()); 1434 } 1435 1436 String toJSONValue() { 1437 return this.jsonValue; 1438 } 1439 } 1440 1441 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role, 1442 Boolean notify, Boolean canViewPath) { 1443 1444 JsonObject itemField = new JsonObject(); 1445 itemField.add("id", this.getID()); 1446 itemField.add("type", "file"); 1447 1448 return BoxCollaboration.create(this.getAPI(), accessibleByField, itemField, role, notify, canViewPath); 1449 } 1450 1451 /** 1452 * Adds a collaborator to this file. 1453 * 1454 * @param collaborator the collaborator to add. 1455 * @param role the role of the collaborator. 1456 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1457 * @param canViewPath whether view path collaboration feature is enabled or not. 1458 * @return info about the new collaboration. 1459 */ 1460 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role, 1461 Boolean notify, Boolean canViewPath) { 1462 JsonObject accessibleByField = new JsonObject(); 1463 accessibleByField.add("id", collaborator.getID()); 1464 1465 if (collaborator instanceof BoxUser) { 1466 accessibleByField.add("type", "user"); 1467 } else if (collaborator instanceof BoxGroup) { 1468 accessibleByField.add("type", "group"); 1469 } else { 1470 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 1471 } 1472 return this.collaborate(accessibleByField, role, notify, canViewPath); 1473 } 1474 1475 1476 /** 1477 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 1478 * account. 1479 * 1480 * @param email the email address of the collaborator to add. 1481 * @param role the role of the collaborator. 1482 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1483 * @param canViewPath whether view path collaboration feature is enabled or not. 1484 * @return info about the new collaboration. 1485 */ 1486 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role, 1487 Boolean notify, Boolean canViewPath) { 1488 JsonObject accessibleByField = new JsonObject(); 1489 accessibleByField.add("login", email); 1490 accessibleByField.add("type", "user"); 1491 1492 return this.collaborate(accessibleByField, role, notify, canViewPath); 1493 } 1494 1495 /** 1496 * Used to retrieve all collaborations associated with the item. 1497 * 1498 * @param fields the optional fields to retrieve. 1499 * @return An iterable of metadata instances associated with the item. 1500 */ 1501 public BoxResourceIterable<BoxCollaboration.Info> getAllFileCollaborations(String... fields) { 1502 return BoxCollaboration.getAllFileCollaborations(this.getAPI(), this.getID(), 1503 GET_COLLABORATORS_PAGE_SIZE, fields); 1504 1505 } 1506}