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