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 * @deprecated This method will be removed in future versions of the SDK; use canUploadVersion(String, long) instead 522 */ 523 @Deprecated 524 public void canUploadVersion(String name, long fileSize, String parentID) { 525 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 526 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 527 528 JsonObject parent = new JsonObject(); 529 parent.add("id", parentID); 530 531 JsonObject preflightInfo = new JsonObject(); 532 preflightInfo.add("parent", parent); 533 if (name != null) { 534 preflightInfo.add("name", name); 535 } 536 537 preflightInfo.add("size", fileSize); 538 539 request.setBody(preflightInfo.toString()); 540 BoxAPIResponse response = request.send(); 541 response.disconnect(); 542 } 543 544 /** 545 * Checks if a new version of the file can be uploaded with the specified name. 546 * @param name the new name for the file. 547 * @return whether or not the file version can be uploaded. 548 */ 549 public boolean canUploadVersion(String name) { 550 return this.canUploadVersion(name, 0); 551 } 552 553 /** 554 * Checks if a new version of the file can be uploaded with the specified name and size. 555 * @param name the new name for the file. 556 * @param fileSize the size of the new version content in bytes. 557 * @return whether or not the file version can be uploaded. 558 */ 559 public boolean canUploadVersion(String name, long fileSize) { 560 561 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 562 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 563 564 JsonObject preflightInfo = new JsonObject(); 565 if (name != null) { 566 preflightInfo.add("name", name); 567 } 568 569 preflightInfo.add("size", fileSize); 570 571 request.setBody(preflightInfo.toString()); 572 try { 573 BoxAPIResponse response = request.send(); 574 575 return response.getResponseCode() == 200; 576 } catch (BoxAPIException ex) { 577 578 if (ex.getResponseCode() >= 400 && ex.getResponseCode() < 500) { 579 // This looks like an error response, menaing the upload would fail 580 return false; 581 } else { 582 // This looks like a network error or server error, rethrow exception 583 throw ex; 584 } 585 } 586 } 587 588 /** 589 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 590 * will be able to view and recover previous versions of the file. 591 * 592 * @param fileContent a stream containing the new file contents. 593 * @deprecated use uploadNewVersion() instead. 594 */ 595 @Deprecated 596 public void uploadVersion(InputStream fileContent) { 597 this.uploadVersion(fileContent, null); 598 } 599 600 /** 601 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 602 * will be able to view and recover previous versions of the file. 603 * 604 * @param fileContent a stream containing the new file contents. 605 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 606 * @deprecated use uploadNewVersion() instead. 607 */ 608 @Deprecated 609 public void uploadVersion(InputStream fileContent, String fileContentSHA1) { 610 this.uploadVersion(fileContent, fileContentSHA1, null); 611 } 612 613 /** 614 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 615 * will be able to view and recover previous versions of the file. 616 * 617 * @param fileContent a stream containing the new file contents. 618 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 619 * @param modified the date that the new version was modified. 620 * @deprecated use uploadNewVersion() instead. 621 */ 622 @Deprecated 623 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 624 this.uploadVersion(fileContent, fileContentSHA1, modified, 0, null); 625 } 626 627 /** 628 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 629 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 630 * of the file. 631 * 632 * @param fileContent a stream containing the new file contents. 633 * @param modified the date that the new version was modified. 634 * @param fileSize the size of the file used for determining the progress of the upload. 635 * @param listener a listener for monitoring the upload's progress. 636 * @deprecated use uploadNewVersion() instead. 637 */ 638 @Deprecated 639 public void uploadVersion(InputStream fileContent, Date modified, long fileSize, ProgressListener listener) { 640 this.uploadVersion(fileContent, null, modified, fileSize, listener); 641 } 642 643 /** 644 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 645 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 646 * of the file. 647 * 648 * @param fileContent a stream containing the new file contents. 649 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 650 * @param modified the date that the new version was modified. 651 * @param fileSize the size of the file used for determining the progress of the upload. 652 * @param listener a listener for monitoring the upload's progress. 653 * @deprecated use uploadNewVersion() instead. 654 */ 655 @Deprecated 656 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 657 ProgressListener listener) { 658 this.uploadNewVersion(fileContent, fileContentSHA1, modified, fileSize, listener); 659 return; 660 } 661 662 /** 663 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 664 * will be able to view and recover previous versions of the file. 665 * 666 * @param fileContent a stream containing the new file contents. 667 * @return the uploaded file version. 668 */ 669 public BoxFile.Info uploadNewVersion(InputStream fileContent) { 670 return this.uploadNewVersion(fileContent, null); 671 } 672 673 /** 674 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 675 * will be able to view and recover previous versions of the file. 676 * 677 * @param fileContent a stream containing the new file contents. 678 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 679 * @return the uploaded file version. 680 */ 681 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1) { 682 return this.uploadNewVersion(fileContent, fileContentSHA1, null); 683 } 684 685 /** 686 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 687 * will be able to view and recover previous versions of the file. 688 * 689 * @param fileContent a stream containing the new file contents. 690 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 691 * @param modified the date that the new version was modified. 692 * @return the uploaded file version. 693 */ 694 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 695 return this.uploadNewVersion(fileContent, fileContentSHA1, modified, 0, null); 696 } 697 698 /** 699 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 700 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 701 * of the file. 702 * 703 * @param fileContent a stream containing the new file contents. 704 * @param modified the date that the new version was modified. 705 * @param fileSize the size of the file used for determining the progress of the upload. 706 * @param listener a listener for monitoring the upload's progress. 707 * @return the uploaded file version. 708 */ 709 public BoxFile.Info uploadNewVersion(InputStream fileContent, Date modified, long fileSize, 710 ProgressListener listener) { 711 return this.uploadNewVersion(fileContent, null, modified, fileSize, listener); 712 } 713 714 /** 715 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 716 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 717 * of the file. 718 * 719 * @param fileContent a stream containing the new file contents. 720 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 721 * @param modified the date that the new version was modified. 722 * @param fileSize the size of the file used for determining the progress of the upload. 723 * @param listener a listener for monitoring the upload's progress. 724 * @return the uploaded file version. 725 */ 726 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 727 ProgressListener listener) { 728 URL uploadURL = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 729 BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL); 730 731 if (fileSize > 0) { 732 request.setFile(fileContent, "", fileSize); 733 } else { 734 request.setFile(fileContent, ""); 735 } 736 737 if (fileContentSHA1 != null) { 738 request.setContentSHA1(fileContentSHA1); 739 } 740 741 if (modified != null) { 742 request.putField("content_modified_at", modified); 743 } 744 745 BoxJSONResponse response; 746 if (listener == null) { 747 response = (BoxJSONResponse) request.send(); 748 } else { 749 response = (BoxJSONResponse) request.send(listener); 750 } 751 752 return new BoxFile.Info(response.getJSON()); 753 } 754 755 /** 756 * Gets an expiring URL for creating an embedded preview session. The URL will expire after 60 seconds and the 757 * preview session will expire after 60 minutes. 758 * 759 * @return the expiring preview link 760 */ 761 public URL getPreviewLink() { 762 BoxFile.Info info = this.getInfo("expiring_embed_link"); 763 764 return info.getPreviewLink(); 765 } 766 767 768 /** 769 * Retrieves a thumbnail, or smaller image representation, of this file. Sizes of 32x32, 64x64, 128x128, 770 * and 256x256 can be returned in the .png format and sizes of 32x32, 94x94, 160x160, and 320x320 can be returned 771 * in the .jpg format. 772 * 773 * @param fileType either PNG of JPG 774 * @param minWidth minimum width 775 * @param minHeight minimum height 776 * @param maxWidth maximum width 777 * @param maxHeight maximum height 778 * @return the byte array of the thumbnail image 779 */ 780 public byte[] getThumbnail(ThumbnailFileType fileType, int minWidth, int minHeight, int maxWidth, int maxHeight) { 781 QueryStringBuilder builder = new QueryStringBuilder(); 782 builder.appendParam("min_width", minWidth); 783 builder.appendParam("min_height", minHeight); 784 builder.appendParam("max_width", maxWidth); 785 builder.appendParam("max_height", maxHeight); 786 787 URLTemplate template; 788 if (fileType == ThumbnailFileType.PNG) { 789 template = GET_THUMBNAIL_PNG_TEMPLATE; 790 } else if (fileType == ThumbnailFileType.JPG) { 791 template = GET_THUMBNAIL_JPG_TEMPLATE; 792 } else { 793 throw new BoxAPIException("Unsupported thumbnail file type"); 794 } 795 URL url = template.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID()); 796 797 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 798 BoxAPIResponse response = request.send(); 799 800 ByteArrayOutputStream thumbOut = new ByteArrayOutputStream(); 801 InputStream body = response.getBody(); 802 byte[] buffer = new byte[BUFFER_SIZE]; 803 try { 804 int n = body.read(buffer); 805 while (n != -1) { 806 thumbOut.write(buffer, 0, n); 807 n = body.read(buffer); 808 } 809 } catch (IOException e) { 810 throw new BoxAPIException("Error reading thumbnail bytes from response body", e); 811 } finally { 812 response.disconnect(); 813 } 814 815 return thumbOut.toByteArray(); 816 } 817 818 /** 819 * Gets a list of any comments on this file. 820 * 821 * @return a list of comments on this file. 822 */ 823 public List<BoxComment.Info> getComments() { 824 URL url = GET_COMMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 825 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 826 BoxJSONResponse response = (BoxJSONResponse) request.send(); 827 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 828 829 int totalCount = responseJSON.get("total_count").asInt(); 830 List<BoxComment.Info> comments = new ArrayList<BoxComment.Info>(totalCount); 831 JsonArray entries = responseJSON.get("entries").asArray(); 832 for (JsonValue value : entries) { 833 JsonObject commentJSON = value.asObject(); 834 BoxComment comment = new BoxComment(this.getAPI(), commentJSON.get("id").asString()); 835 BoxComment.Info info = comment.new Info(commentJSON); 836 comments.add(info); 837 } 838 839 return comments; 840 } 841 842 /** 843 * Gets a list of any tasks on this file. 844 * 845 * @return a list of tasks on this file. 846 */ 847 public List<BoxTask.Info> getTasks() { 848 URL url = GET_TASKS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 849 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 850 BoxJSONResponse response = (BoxJSONResponse) request.send(); 851 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 852 853 int totalCount = responseJSON.get("total_count").asInt(); 854 List<BoxTask.Info> tasks = new ArrayList<BoxTask.Info>(totalCount); 855 JsonArray entries = responseJSON.get("entries").asArray(); 856 for (JsonValue value : entries) { 857 JsonObject taskJSON = value.asObject(); 858 BoxTask task = new BoxTask(this.getAPI(), taskJSON.get("id").asString()); 859 BoxTask.Info info = task.new Info(taskJSON); 860 tasks.add(info); 861 } 862 863 return tasks; 864 } 865 866 /** 867 * Creates metadata on this file in the global properties template. 868 * 869 * @param metadata The new metadata values. 870 * @return the metadata returned from the server. 871 */ 872 public Metadata createMetadata(Metadata metadata) { 873 return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata); 874 } 875 876 /** 877 * Creates metadata on this file in the specified template type. 878 * 879 * @param typeName the metadata template type name. 880 * @param metadata the new metadata values. 881 * @return the metadata returned from the server. 882 */ 883 public Metadata createMetadata(String typeName, Metadata metadata) { 884 String scope = Metadata.scopeBasedOnType(typeName); 885 return this.createMetadata(typeName, scope, metadata); 886 } 887 888 /** 889 * Creates metadata on this file in the specified template type. 890 * 891 * @param typeName the metadata template type name. 892 * @param scope the metadata scope (global or enterprise). 893 * @param metadata the new metadata values. 894 * @return the metadata returned from the server. 895 */ 896 public Metadata createMetadata(String typeName, String scope, Metadata metadata) { 897 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 898 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST"); 899 request.addHeader("Content-Type", "application/json"); 900 request.setBody(metadata.toString()); 901 BoxJSONResponse response = (BoxJSONResponse) request.send(); 902 return new Metadata(JsonObject.readFrom(response.getJSON())); 903 } 904 905 /** 906 * Locks a file. 907 * 908 * @return the lock returned from the server. 909 */ 910 public BoxLock lock() { 911 return this.lock(null, false); 912 } 913 914 /** 915 * Locks a file. 916 * 917 * @param isDownloadPrevented is downloading of file prevented when locked. 918 * @return the lock returned from the server. 919 */ 920 public BoxLock lock(boolean isDownloadPrevented) { 921 return this.lock(null, isDownloadPrevented); 922 } 923 924 /** 925 * Locks a file. 926 * 927 * @param expiresAt expiration date of the lock. 928 * @return the lock returned from the server. 929 */ 930 public BoxLock lock(Date expiresAt) { 931 return this.lock(expiresAt, false); 932 } 933 934 /** 935 * Locks a file. 936 * 937 * @param expiresAt expiration date of the lock. 938 * @param isDownloadPrevented is downloading of file prevented when locked. 939 * @return the lock returned from the server. 940 */ 941 public BoxLock lock(Date expiresAt, boolean isDownloadPrevented) { 942 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 943 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 944 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 945 946 JsonObject lockConfig = new JsonObject(); 947 lockConfig.add("type", "lock"); 948 if (expiresAt != null) { 949 lockConfig.add("expires_at", BoxDateFormat.format(expiresAt)); 950 } 951 lockConfig.add("is_download_prevented", isDownloadPrevented); 952 953 JsonObject requestJSON = new JsonObject(); 954 requestJSON.add("lock", lockConfig); 955 request.setBody(requestJSON.toString()); 956 957 BoxJSONResponse response = (BoxJSONResponse) request.send(); 958 959 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 960 JsonValue lockValue = responseJSON.get("lock"); 961 JsonObject lockJSON = JsonObject.readFrom(lockValue.toString()); 962 963 return new BoxLock(lockJSON, this.getAPI()); 964 } 965 966 /** 967 * Unlocks a file. 968 */ 969 public void unlock() { 970 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 971 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 972 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 973 974 JsonObject lockObject = new JsonObject(); 975 lockObject.add("lock", JsonObject.NULL); 976 977 request.setBody(lockObject.toString()); 978 request.send(); 979 } 980 981 /** 982 * Used to retrieve all metadata associated with the file. 983 * 984 * @param fields the optional fields to retrieve. 985 * @return An iterable of metadata instances associated with the file. 986 */ 987 public Iterable<Metadata> getAllMetadata(String... fields) { 988 return Metadata.getAllMetadata(this, fields); 989 } 990 991 /** 992 * Gets the file properties metadata. 993 * 994 * @return the metadata returned from the server. 995 */ 996 public Metadata getMetadata() { 997 return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE); 998 } 999 1000 /** 1001 * Gets the file metadata of specified template type. 1002 * 1003 * @param typeName the metadata template type name. 1004 * @return the metadata returned from the server. 1005 */ 1006 public Metadata getMetadata(String typeName) { 1007 String scope = Metadata.scopeBasedOnType(typeName); 1008 return this.getMetadata(typeName, scope); 1009 } 1010 1011 /** 1012 * Gets the file metadata of specified template type. 1013 * 1014 * @param typeName the metadata template type name. 1015 * @param scope the metadata scope (global or enterprise). 1016 * @return the metadata returned from the server. 1017 */ 1018 public Metadata getMetadata(String typeName, String scope) { 1019 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1020 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 1021 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1022 return new Metadata(JsonObject.readFrom(response.getJSON())); 1023 } 1024 1025 /** 1026 * Updates the file metadata. 1027 * 1028 * @param metadata the new metadata values. 1029 * @return the metadata returned from the server. 1030 */ 1031 public Metadata updateMetadata(Metadata metadata) { 1032 String scope; 1033 if (metadata.getScope().equals(Metadata.GLOBAL_METADATA_SCOPE)) { 1034 scope = Metadata.GLOBAL_METADATA_SCOPE; 1035 } else { 1036 scope = Metadata.ENTERPRISE_METADATA_SCOPE; 1037 } 1038 1039 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), 1040 scope, metadata.getTemplateName()); 1041 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 1042 request.addHeader("Content-Type", "application/json-patch+json"); 1043 request.setBody(metadata.getPatch()); 1044 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1045 return new Metadata(JsonObject.readFrom(response.getJSON())); 1046 } 1047 1048 /** 1049 * Deletes the file properties metadata. 1050 */ 1051 public void deleteMetadata() { 1052 this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE); 1053 } 1054 1055 /** 1056 * Deletes the file metadata of specified template type. 1057 * 1058 * @param typeName the metadata template type name. 1059 */ 1060 public void deleteMetadata(String typeName) { 1061 String scope = Metadata.scopeBasedOnType(typeName); 1062 this.deleteMetadata(typeName, scope); 1063 } 1064 1065 /** 1066 * Deletes the file metadata of specified template type. 1067 * 1068 * @param typeName the metadata template type name. 1069 * @param scope the metadata scope (global or enterprise). 1070 */ 1071 public void deleteMetadata(String typeName, String scope) { 1072 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1073 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 1074 request.send(); 1075 } 1076 1077 /** 1078 * Used to retrieve the watermark for the file. 1079 * If the file does not have a watermark applied to it, a 404 Not Found will be returned by API. 1080 * 1081 * @param fields the fields to retrieve. 1082 * @return the watermark associated with the file. 1083 */ 1084 public BoxWatermark getWatermark(String... fields) { 1085 return this.getWatermark(FILE_URL_TEMPLATE, fields); 1086 } 1087 1088 /** 1089 * Used to apply or update the watermark for the file. 1090 * 1091 * @return the watermark associated with the file. 1092 */ 1093 public BoxWatermark applyWatermark() { 1094 return this.applyWatermark(FILE_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT); 1095 } 1096 1097 /** 1098 * Removes a watermark from the file. 1099 * If the file did not have a watermark applied to it, a 404 Not Found will be returned by API. 1100 */ 1101 public void removeWatermark() { 1102 this.removeWatermark(FILE_URL_TEMPLATE); 1103 } 1104 1105 /** 1106 * {@inheritDoc} 1107 */ 1108 @Override 1109 public BoxFile.Info setCollections(BoxCollection... collections) { 1110 JsonArray jsonArray = new JsonArray(); 1111 for (BoxCollection collection : collections) { 1112 JsonObject collectionJSON = new JsonObject(); 1113 collectionJSON.add("id", collection.getID()); 1114 jsonArray.add(collectionJSON); 1115 } 1116 JsonObject infoJSON = new JsonObject(); 1117 infoJSON.add("collections", jsonArray); 1118 1119 String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString(); 1120 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 1121 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 1122 request.setBody(infoJSON.toString()); 1123 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1124 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1125 return new Info(jsonObject); 1126 } 1127 1128 /** 1129 * Creates an upload session to create a new version of a file in chunks. 1130 * This will first verify that the version can be created and then open a session for uploading pieces of the file. 1131 * @param fileSize the size of the file that will be uploaded. 1132 * @return the created upload session instance. 1133 */ 1134 public BoxFileUploadSession.Info createUploadSession(long fileSize) { 1135 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1136 1137 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 1138 request.addHeader("Content-Type", "application/json"); 1139 1140 JsonObject body = new JsonObject(); 1141 body.add("file_size", fileSize); 1142 request.setBody(body.toString()); 1143 1144 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1145 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1146 1147 String sessionId = jsonObject.get("id").asString(); 1148 BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId); 1149 return session.new Info(jsonObject); 1150 } 1151 1152 /** 1153 * Creates a new version of a file. 1154 * @param inputStream the stream instance that contains the data. 1155 * @param fileSize the size of the file that will be uploaded. 1156 * @return the created file instance. 1157 * @throws InterruptedException when a thread execution is interrupted. 1158 * @throws IOException when reading a stream throws exception. 1159 */ 1160 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize) 1161 throws InterruptedException, IOException { 1162 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1163 return new LargeFileUpload().upload(this.getAPI(), inputStream, url, fileSize); 1164 } 1165 1166 /** 1167 * Creates a new version of a file using specified number of parallel http connections. 1168 * @param inputStream the stream instance that contains the data. 1169 * @param fileSize the size of the file that will be uploaded. 1170 * @param nParallelConnections number of parallel http connections to use 1171 * @param timeOut time to wait before killing the job 1172 * @param unit time unit for the time wait value 1173 * @return the created file instance. 1174 * @throws InterruptedException when a thread execution is interrupted. 1175 * @throws IOException when reading a stream throws exception. 1176 */ 1177 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize, 1178 int nParallelConnections, long timeOut, TimeUnit unit) 1179 throws InterruptedException, IOException { 1180 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1181 return new LargeFileUpload(nParallelConnections, timeOut, unit) 1182 .upload(this.getAPI(), inputStream, url, fileSize); 1183 } 1184 1185 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role, 1186 Boolean notify, Boolean canViewPath) { 1187 1188 JsonObject itemField = new JsonObject(); 1189 itemField.add("id", this.getID()); 1190 itemField.add("type", "file"); 1191 1192 return BoxCollaboration.create(this.getAPI(), accessibleByField, itemField, role, notify, canViewPath); 1193 } 1194 1195 /** 1196 * Adds a collaborator to this file. 1197 * 1198 * @param collaborator the collaborator to add. 1199 * @param role the role of the collaborator. 1200 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1201 * @param canViewPath whether view path collaboration feature is enabled or not. 1202 * @return info about the new collaboration. 1203 */ 1204 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role, 1205 Boolean notify, Boolean canViewPath) { 1206 JsonObject accessibleByField = new JsonObject(); 1207 accessibleByField.add("id", collaborator.getID()); 1208 1209 if (collaborator instanceof BoxUser) { 1210 accessibleByField.add("type", "user"); 1211 } else if (collaborator instanceof BoxGroup) { 1212 accessibleByField.add("type", "group"); 1213 } else { 1214 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 1215 } 1216 return this.collaborate(accessibleByField, role, notify, canViewPath); 1217 } 1218 1219 1220 /** 1221 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 1222 * account. 1223 * 1224 * @param email the email address of the collaborator to add. 1225 * @param role the role of the collaborator. 1226 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1227 * @param canViewPath whether view path collaboration feature is enabled or not. 1228 * @return info about the new collaboration. 1229 */ 1230 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role, 1231 Boolean notify, Boolean canViewPath) { 1232 JsonObject accessibleByField = new JsonObject(); 1233 accessibleByField.add("login", email); 1234 accessibleByField.add("type", "user"); 1235 1236 return this.collaborate(accessibleByField, role, notify, canViewPath); 1237 } 1238 1239 /** 1240 * Used to retrieve all collaborations associated with the item. 1241 * 1242 * @param fields the optional fields to retrieve. 1243 * @return An iterable of metadata instances associated with the item. 1244 */ 1245 public BoxResourceIterable<BoxCollaboration.Info> getAllFileCollaborations(String... fields) { 1246 return BoxCollaboration.getAllFileCollaborations(this.getAPI(), this.getID(), 1247 GET_COLLABORATORS_PAGE_SIZE, fields); 1248 1249 } 1250 1251 /** 1252 * Contains information about a BoxFile. 1253 */ 1254 public class Info extends BoxItem.Info { 1255 private String sha1; 1256 private String versionNumber; 1257 private long commentCount; 1258 private EnumSet<Permission> permissions; 1259 private String extension; 1260 private boolean isPackage; 1261 private BoxFileVersion version; 1262 private URL previewLink; 1263 private BoxLock lock; 1264 private boolean isWatermarked; 1265 private JsonObject metadata; 1266 private Map<String, Map<String, Metadata>> metadataMap; 1267 private List<Representation> representations; 1268 1269 /** 1270 * Constructs an empty Info object. 1271 */ 1272 public Info() { 1273 super(); 1274 } 1275 1276 /** 1277 * Constructs an Info object by parsing information from a JSON string. 1278 * 1279 * @param json the JSON string to parse. 1280 */ 1281 public Info(String json) { 1282 super(json); 1283 } 1284 1285 /** 1286 * Constructs an Info object using an already parsed JSON object. 1287 * 1288 * @param jsonObject the parsed JSON object. 1289 */ 1290 public Info(JsonObject jsonObject) { 1291 super(jsonObject); 1292 } 1293 1294 @Override 1295 public BoxFile getResource() { 1296 return BoxFile.this; 1297 } 1298 1299 /** 1300 * Gets the SHA1 hash of the file. 1301 * 1302 * @return the SHA1 hash of the file. 1303 */ 1304 public String getSha1() { 1305 return this.sha1; 1306 } 1307 1308 /** 1309 * Gets the lock of the file. 1310 * 1311 * @return the lock of the file. 1312 */ 1313 public BoxLock getLock() { 1314 return this.lock; 1315 } 1316 1317 /** 1318 * Gets the current version number of the file. 1319 * 1320 * @return the current version number of the file. 1321 */ 1322 public String getVersionNumber() { 1323 return this.versionNumber; 1324 } 1325 1326 /** 1327 * Gets the number of comments on the file. 1328 * 1329 * @return the number of comments on the file. 1330 */ 1331 public long getCommentCount() { 1332 return this.commentCount; 1333 } 1334 1335 /** 1336 * Gets the permissions that the current user has on the file. 1337 * 1338 * @return the permissions that the current user has on the file. 1339 */ 1340 public EnumSet<Permission> getPermissions() { 1341 return this.permissions; 1342 } 1343 1344 /** 1345 * Gets the extension suffix of the file, excluding the dot. 1346 * 1347 * @return the extension of the file. 1348 */ 1349 public String getExtension() { 1350 return this.extension; 1351 } 1352 1353 /** 1354 * Gets whether or not the file is an OSX package. 1355 * 1356 * @return true if the file is an OSX package; otherwise false. 1357 */ 1358 public boolean getIsPackage() { 1359 return this.isPackage; 1360 } 1361 1362 /** 1363 * Gets the current version details of the file. 1364 * 1365 * @return the current version details of the file. 1366 */ 1367 public BoxFileVersion getVersion() { 1368 return this.version; 1369 } 1370 1371 /** 1372 * Gets the current expiring preview link. 1373 * 1374 * @return the expiring preview link 1375 */ 1376 public URL getPreviewLink() { 1377 return this.previewLink; 1378 } 1379 1380 /** 1381 * Gets flag indicating whether this file is Watermarked. 1382 * 1383 * @return whether the file is watermarked or not 1384 */ 1385 public boolean getIsWatermarked() { 1386 return this.isWatermarked; 1387 } 1388 1389 /** 1390 * Gets the metadata on this file associated with a specified scope and template. 1391 * Makes an attempt to get metadata that was retrieved using getInfo(String ...) method. If no result is found 1392 * then makes an API call to get metadata 1393 * @param templateName the metadata template type name. 1394 * @param scope the scope of the template (usually "global" or "enterprise"). 1395 * @return the metadata returned from the server. 1396 */ 1397 public Metadata getMetadata(String templateName, String scope) { 1398 try { 1399 return this.metadataMap.get(scope).get(templateName); 1400 } catch (NullPointerException e) { 1401 return null; 1402 } 1403 } 1404 1405 /** 1406 * Get file's representations. 1407 * @return list of representations 1408 */ 1409 public List<Representation> getRepresentations() { 1410 return this.representations; 1411 } 1412 1413 @Override 1414 protected void parseJSONMember(JsonObject.Member member) { 1415 super.parseJSONMember(member); 1416 1417 String memberName = member.getName(); 1418 JsonValue value = member.getValue(); 1419 if (memberName.equals("sha1")) { 1420 this.sha1 = value.asString(); 1421 } else if (memberName.equals("version_number")) { 1422 this.versionNumber = value.asString(); 1423 } else if (memberName.equals("comment_count")) { 1424 this.commentCount = value.asLong(); 1425 } else if (memberName.equals("permissions")) { 1426 this.permissions = this.parsePermissions(value.asObject()); 1427 } else if (memberName.equals("extension")) { 1428 this.extension = value.asString(); 1429 } else if (memberName.equals("is_package")) { 1430 this.isPackage = value.asBoolean(); 1431 } else if (memberName.equals("file_version")) { 1432 this.version = this.parseFileVersion(value.asObject()); 1433 } else if (memberName.equals("expiring_embed_link")) { 1434 try { 1435 String urlString = member.getValue().asObject().get("url").asString(); 1436 this.previewLink = new URL(urlString); 1437 } catch (MalformedURLException e) { 1438 throw new BoxAPIException("Couldn't parse expiring_embed_link/url for file", e); 1439 } 1440 } else if (memberName.equals("lock")) { 1441 if (value.isNull()) { 1442 this.lock = null; 1443 } else { 1444 this.lock = new BoxLock(value.asObject(), BoxFile.this.getAPI()); 1445 } 1446 } else if (memberName.equals("watermark_info")) { 1447 JsonObject jsonObject = value.asObject(); 1448 this.isWatermarked = jsonObject.get("is_watermarked").asBoolean(); 1449 } else if (memberName.equals("metadata")) { 1450 JsonObject jsonObject = value.asObject(); 1451 this.metadataMap = Parsers.parseAndPopulateMetadataMap(jsonObject); 1452 } else if (memberName.equals("representations")) { 1453 JsonObject jsonObject = value.asObject(); 1454 this.representations = Parsers.parseRepresentations(jsonObject); 1455 } 1456 } 1457 1458 private EnumSet<Permission> parsePermissions(JsonObject jsonObject) { 1459 EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class); 1460 for (JsonObject.Member member : jsonObject) { 1461 JsonValue value = member.getValue(); 1462 if (value.isNull() || !value.asBoolean()) { 1463 continue; 1464 } 1465 1466 String memberName = member.getName(); 1467 if (memberName.equals("can_download")) { 1468 permissions.add(Permission.CAN_DOWNLOAD); 1469 } else if (memberName.equals("can_upload")) { 1470 permissions.add(Permission.CAN_UPLOAD); 1471 } else if (memberName.equals("can_rename")) { 1472 permissions.add(Permission.CAN_RENAME); 1473 } else if (memberName.equals("can_delete")) { 1474 permissions.add(Permission.CAN_DELETE); 1475 } else if (memberName.equals("can_share")) { 1476 permissions.add(Permission.CAN_SHARE); 1477 } else if (memberName.equals("can_set_share_access")) { 1478 permissions.add(Permission.CAN_SET_SHARE_ACCESS); 1479 } else if (memberName.equals("can_preview")) { 1480 permissions.add(Permission.CAN_PREVIEW); 1481 } else if (memberName.equals("can_comment")) { 1482 permissions.add(Permission.CAN_COMMENT); 1483 } 1484 } 1485 1486 return permissions; 1487 } 1488 1489 private BoxFileVersion parseFileVersion(JsonObject jsonObject) { 1490 return new BoxFileVersion(BoxFile.this.getAPI(), jsonObject, BoxFile.this.getID()); 1491 } 1492 } 1493 1494 /** 1495 * Enumerates the possible permissions that a user can have on a file. 1496 */ 1497 public enum Permission { 1498 /** 1499 * The user can download the file. 1500 */ 1501 CAN_DOWNLOAD("can_download"), 1502 1503 /** 1504 * The user can upload new versions of the file. 1505 */ 1506 CAN_UPLOAD("can_upload"), 1507 1508 /** 1509 * The user can rename the file. 1510 */ 1511 CAN_RENAME("can_rename"), 1512 1513 /** 1514 * The user can delete the file. 1515 */ 1516 CAN_DELETE("can_delete"), 1517 1518 /** 1519 * The user can share the file. 1520 */ 1521 CAN_SHARE("can_share"), 1522 1523 /** 1524 * The user can set the access level for shared links to the file. 1525 */ 1526 CAN_SET_SHARE_ACCESS("can_set_share_access"), 1527 1528 /** 1529 * The user can preview the file. 1530 */ 1531 CAN_PREVIEW("can_preview"), 1532 1533 /** 1534 * The user can comment on the file. 1535 */ 1536 CAN_COMMENT("can_comment"); 1537 1538 private final String jsonValue; 1539 1540 private Permission(String jsonValue) { 1541 this.jsonValue = jsonValue; 1542 } 1543 1544 static Permission fromJSONValue(String jsonValue) { 1545 return Permission.valueOf(jsonValue.toUpperCase()); 1546 } 1547 1548 String toJSONValue() { 1549 return this.jsonValue; 1550 } 1551 } 1552 1553}