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.http.HttpMethod; 021import com.box.sdk.internal.utils.Parsers; 022import com.eclipsesource.json.JsonArray; 023import com.eclipsesource.json.JsonObject; 024import com.eclipsesource.json.JsonValue; 025 026 027/** 028 * Represents an individual file on Box. This class can be used to download a file's contents, upload new versions, and 029 * perform other common file operations (move, copy, delete, etc.). 030 * 031 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 032 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 033 * handling for errors related to the Box REST API, you should capture this exception explicitly. 034 */ 035@BoxResourceType("file") 036public class BoxFile extends BoxItem { 037 038 /** 039 * An array of all possible file fields that can be requested when calling {@link #getInfo()}. 040 */ 041 public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "sha1", "name", 042 "description", "size", "path_collection", "created_at", "modified_at", 043 "trashed_at", "purged_at", "content_created_at", "content_modified_at", 044 "created_by", "modified_by", "owned_by", "shared_link", "parent", 045 "item_status", "version_number", "comment_count", "permissions", "tags", 046 "lock", "extension", "is_package", "file_version", "collections", 047 "watermark_info", "metadata", "representations", 048 "is_external_only", "expiring_embed_link", "allowed_invitee_roles", 049 "has_collaborations"}; 050 051 /** 052 * Used to specify what filetype to request for a file thumbnail. 053 */ 054 public enum ThumbnailFileType { 055 /** 056 * PNG image format. 057 */ 058 PNG, 059 060 /** 061 * JPG image format. 062 */ 063 JPG 064 } 065 066 /** 067 * File URL Template. 068 */ 069 public static final URLTemplate FILE_URL_TEMPLATE = new URLTemplate("files/%s"); 070 /** 071 * Content URL Template. 072 */ 073 public static final URLTemplate CONTENT_URL_TEMPLATE = new URLTemplate("files/%s/content"); 074 /** 075 * Versions URL Template. 076 */ 077 public static final URLTemplate VERSIONS_URL_TEMPLATE = new URLTemplate("files/%s/versions"); 078 /** 079 * Copy URL Template. 080 */ 081 public static final URLTemplate COPY_URL_TEMPLATE = new URLTemplate("files/%s/copy"); 082 /** 083 * Add Comment URL Template. 084 */ 085 public static final URLTemplate ADD_COMMENT_URL_TEMPLATE = new URLTemplate("comments"); 086 /** 087 * Get Comments URL Template. 088 */ 089 public static final URLTemplate GET_COMMENTS_URL_TEMPLATE = new URLTemplate("files/%s/comments"); 090 /** 091 * Metadata URL Template. 092 */ 093 public static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("files/%s/metadata/%s/%s"); 094 /** 095 * Add Task URL Template. 096 */ 097 public static final URLTemplate ADD_TASK_URL_TEMPLATE = new URLTemplate("tasks"); 098 /** 099 * Get Tasks URL Template. 100 */ 101 public static final URLTemplate GET_TASKS_URL_TEMPLATE = new URLTemplate("files/%s/tasks"); 102 /** 103 * Get Thumbnail PNG Template. 104 */ 105 public static final URLTemplate GET_THUMBNAIL_PNG_TEMPLATE = new URLTemplate("files/%s/thumbnail.png"); 106 /** 107 * Get Thumbnail JPG Template. 108 */ 109 public static final URLTemplate GET_THUMBNAIL_JPG_TEMPLATE = new URLTemplate("files/%s/thumbnail.jpg"); 110 /** 111 * Upload Session URL Template. 112 */ 113 public static final URLTemplate UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/%s/upload_sessions"); 114 /** 115 * Upload Session Status URL Template. 116 */ 117 public static final URLTemplate UPLOAD_SESSION_STATUS_URL_TEMPLATE = new URLTemplate( 118 "files/upload_sessions/%s/status"); 119 /** 120 * Abort Upload Session URL Template. 121 */ 122 public static final URLTemplate ABORT_UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/upload_sessions/%s"); 123 /** 124 * Add Collaborations URL Template. 125 */ 126 public static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations"); 127 /** 128 * Get All File Collaborations URL Template. 129 */ 130 public static final URLTemplate GET_ALL_FILE_COLLABORATIONS_URL = new URLTemplate("files/%s/collaborations"); 131 private static final int BUFFER_SIZE = 8192; 132 private static final int GET_COLLABORATORS_PAGE_SIZE = 1000; 133 134 /** 135 * Constructs a BoxFile for a file with a given ID. 136 * 137 * @param api the API connection to be used by the file. 138 * @param id the ID of the file. 139 */ 140 public BoxFile(BoxAPIConnection api, String id) { 141 super(api, id); 142 } 143 144 /** 145 * {@inheritDoc} 146 */ 147 @Override 148 protected URL getItemURL() { 149 return FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 150 } 151 152 @Override 153 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 154 BoxSharedLink.Permissions permissions) { 155 156 BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions); 157 Info info = new Info(); 158 info.setSharedLink(sharedLink); 159 160 this.updateInfo(info); 161 return info.getSharedLink(); 162 } 163 164 /** 165 * Creates new SharedLink for a BoxFile with a password. 166 * 167 * @param access The access level of the shared link. 168 * @param unshareDate A specified date to unshare the Box file. 169 * @param permissions The permissions to set on the shared link for the Box file. 170 * @param password Password set on the shared link to give access to the Box file. 171 * @return information about the newly created shared link. 172 */ 173 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 174 BoxSharedLink.Permissions permissions, String password) { 175 176 BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions, password); 177 Info info = new Info(); 178 info.setSharedLink(sharedLink); 179 180 this.updateInfo(info); 181 return info.getSharedLink(); 182 } 183 184 /** 185 * Adds new {@link BoxWebHook} to this {@link BoxFile}. 186 * 187 * @param address {@link BoxWebHook.Info#getAddress()} 188 * @param triggers {@link BoxWebHook.Info#getTriggers()} 189 * @return created {@link BoxWebHook.Info} 190 */ 191 public BoxWebHook.Info addWebHook(URL address, BoxWebHook.Trigger... triggers) { 192 return BoxWebHook.create(this, address, triggers); 193 } 194 195 /** 196 * Adds a comment to this file. The message can contain @mentions by using the string @[userid:username] anywhere 197 * within the message, where userid and username are the ID and username of the person being mentioned. 198 * 199 * @param message the comment's message. 200 * @return information about the newly added comment. 201 * @see <a href="https://developers.box.com/docs/#comments-add-a-comment-to-an-item">the tagged_message field 202 * for including @mentions.</a> 203 */ 204 public BoxComment.Info addComment(String message) { 205 JsonObject itemJSON = new JsonObject(); 206 itemJSON.add("type", "file"); 207 itemJSON.add("id", this.getID()); 208 209 JsonObject requestJSON = new JsonObject(); 210 requestJSON.add("item", itemJSON); 211 if (BoxComment.messageContainsMention(message)) { 212 requestJSON.add("tagged_message", message); 213 } else { 214 requestJSON.add("message", message); 215 } 216 217 URL url = ADD_COMMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL()); 218 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 219 request.setBody(requestJSON.toString()); 220 BoxJSONResponse response = (BoxJSONResponse) request.send(); 221 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 222 223 BoxComment addedComment = new BoxComment(this.getAPI(), responseJSON.get("id").asString()); 224 return addedComment.new Info(responseJSON); 225 } 226 227 /** 228 * Adds a new task to this file. The task can have an optional message to include, and a due date. 229 * 230 * @param action the action the task assignee will be prompted to do. 231 * @param message an optional message to include with the task. 232 * @param dueAt the day at which this task is due. 233 * @return information about the newly added task. 234 */ 235 public BoxTask.Info addTask(BoxTask.Action action, String message, Date dueAt) { 236 return this.addTask(action, message, dueAt, null); 237 } 238 239 /** 240 * Adds a new task to this file. The task can have an optional message to include, due date, 241 * and task completion rule. 242 * 243 * @param action the action the task assignee will be prompted to do. 244 * @param message an optional message to include with the task. 245 * @param dueAt the day at which this task is due. 246 * @param completionRule the rule for completing the task. 247 * @return information about the newly added task. 248 */ 249 public BoxTask.Info addTask(BoxTask.Action action, String message, Date dueAt, 250 BoxTask.CompletionRule completionRule) { 251 JsonObject itemJSON = new JsonObject(); 252 itemJSON.add("type", "file"); 253 itemJSON.add("id", this.getID()); 254 255 JsonObject requestJSON = new JsonObject(); 256 requestJSON.add("item", itemJSON); 257 requestJSON.add("action", action.toJSONString()); 258 259 if (message != null && !message.isEmpty()) { 260 requestJSON.add("message", message); 261 } 262 263 if (dueAt != null) { 264 requestJSON.add("due_at", BoxDateFormat.format(dueAt)); 265 } 266 267 if (completionRule != null) { 268 requestJSON.add("completion_rule", completionRule.toJSONString()); 269 } 270 271 URL url = ADD_TASK_URL_TEMPLATE.build(this.getAPI().getBaseURL()); 272 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 273 request.setBody(requestJSON.toString()); 274 BoxJSONResponse response = (BoxJSONResponse) request.send(); 275 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 276 277 BoxTask addedTask = new BoxTask(this.getAPI(), responseJSON.get("id").asString()); 278 return addedTask.new Info(responseJSON); 279 } 280 281 /** 282 * Gets an expiring URL for downloading a file directly from Box. This can be user, 283 * for example, for sending as a redirect to a browser to cause the browser 284 * to download the file directly from Box. 285 * 286 * @return the temporary download URL 287 */ 288 public URL getDownloadURL() { 289 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 290 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 291 request.setFollowRedirects(false); 292 293 BoxRedirectResponse response = (BoxRedirectResponse) request.send(); 294 295 return response.getRedirectURL(); 296 } 297 298 /** 299 * Downloads the contents of this file to a given OutputStream. 300 * 301 * @param output the stream to where the file will be written. 302 */ 303 public void download(OutputStream output) { 304 this.download(output, null); 305 } 306 307 /** 308 * Downloads the contents of this file to a given OutputStream while reporting the progress to a ProgressListener. 309 * 310 * @param output the stream to where the file will be written. 311 * @param listener a listener for monitoring the download's progress. 312 */ 313 public void download(OutputStream output, ProgressListener listener) { 314 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 315 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 316 BoxAPIResponse response = request.send(); 317 InputStream input = response.getBody(listener); 318 319 byte[] buffer = new byte[BUFFER_SIZE]; 320 try { 321 int n = input.read(buffer); 322 while (n != -1) { 323 output.write(buffer, 0, n); 324 n = input.read(buffer); 325 } 326 } catch (IOException e) { 327 throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); 328 } finally { 329 response.disconnect(); 330 } 331 } 332 333 /** 334 * Downloads a part of this file's contents, starting at specified byte offset. 335 * 336 * @param output the stream to where the file will be written. 337 * @param offset the byte offset at which to start the download. 338 */ 339 public void downloadRange(OutputStream output, long offset) { 340 this.downloadRange(output, offset, -1); 341 } 342 343 /** 344 * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd. 345 * 346 * @param output the stream to where the file will be written. 347 * @param rangeStart the byte offset at which to start the download. 348 * @param rangeEnd the byte offset at which to stop the download. 349 */ 350 public void downloadRange(OutputStream output, long rangeStart, long rangeEnd) { 351 this.downloadRange(output, rangeStart, rangeEnd, null); 352 } 353 354 /** 355 * Downloads a part of this file's contents, starting at rangeStart and stopping at rangeEnd, while reporting the 356 * progress to a ProgressListener. 357 * 358 * @param output the stream to where the file will be written. 359 * @param rangeStart the byte offset at which to start the download. 360 * @param rangeEnd the byte offset at which to stop the download. 361 * @param listener a listener for monitoring the download's progress. 362 */ 363 public void downloadRange(OutputStream output, long rangeStart, long rangeEnd, ProgressListener listener) { 364 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 365 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 366 if (rangeEnd > 0) { 367 request.addHeader("Range", String.format("bytes=%s-%s", Long.toString(rangeStart), 368 Long.toString(rangeEnd))); 369 } else { 370 request.addHeader("Range", String.format("bytes=%s-", Long.toString(rangeStart))); 371 } 372 373 BoxAPIResponse response = request.send(); 374 InputStream input = response.getBody(listener); 375 376 byte[] buffer = new byte[BUFFER_SIZE]; 377 try { 378 int n = input.read(buffer); 379 while (n != -1) { 380 output.write(buffer, 0, n); 381 n = input.read(buffer); 382 } 383 } catch (IOException e) { 384 throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); 385 } finally { 386 response.disconnect(); 387 } 388 } 389 390 @Override 391 public BoxFile.Info copy(BoxFolder destination) { 392 return this.copy(destination, null); 393 } 394 395 @Override 396 public BoxFile.Info copy(BoxFolder destination, String newName) { 397 URL url = COPY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 398 399 JsonObject parent = new JsonObject(); 400 parent.add("id", destination.getID()); 401 402 JsonObject copyInfo = new JsonObject(); 403 copyInfo.add("parent", parent); 404 if (newName != null) { 405 copyInfo.add("name", newName); 406 } 407 408 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 409 request.setBody(copyInfo.toString()); 410 BoxJSONResponse response = (BoxJSONResponse) request.send(); 411 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 412 BoxFile copiedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString()); 413 return copiedFile.new Info(responseJSON); 414 } 415 416 /** 417 * Deletes this file by moving it to the trash. 418 */ 419 public void delete() { 420 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 421 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 422 BoxAPIResponse response = request.send(); 423 response.disconnect(); 424 } 425 426 @Override 427 public BoxItem.Info move(BoxFolder destination) { 428 return this.move(destination, null); 429 } 430 431 @Override 432 public BoxItem.Info move(BoxFolder destination, String newName) { 433 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 434 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 435 436 JsonObject parent = new JsonObject(); 437 parent.add("id", destination.getID()); 438 439 JsonObject updateInfo = new JsonObject(); 440 updateInfo.add("parent", parent); 441 if (newName != null) { 442 updateInfo.add("name", newName); 443 } 444 445 request.setBody(updateInfo.toString()); 446 BoxJSONResponse response = (BoxJSONResponse) request.send(); 447 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 448 BoxFile movedFile = new BoxFile(this.getAPI(), responseJSON.get("id").asString()); 449 return movedFile.new Info(responseJSON); 450 } 451 452 /** 453 * Renames this file. 454 * 455 * @param newName the new name of the file. 456 */ 457 public void rename(String newName) { 458 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 459 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 460 461 JsonObject updateInfo = new JsonObject(); 462 updateInfo.add("name", newName); 463 464 request.setBody(updateInfo.toString()); 465 BoxJSONResponse response = (BoxJSONResponse) request.send(); 466 response.getJSON(); 467 } 468 469 @Override 470 public BoxFile.Info getInfo() { 471 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 472 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 473 BoxJSONResponse response = (BoxJSONResponse) request.send(); 474 return new Info(response.getJSON()); 475 } 476 477 @Override 478 public BoxFile.Info getInfo(String... fields) { 479 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 480 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 481 482 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 483 BoxJSONResponse response = (BoxJSONResponse) request.send(); 484 return new Info(response.getJSON()); 485 } 486 487 /** 488 * Gets information about this item including a specified set of representations. 489 * @see <a href=https://developer.box.com/reference#section-x-rep-hints-header>X-Rep-Hints Header</a> 490 * 491 * @param representationHints hints for representations to be retrieved 492 * @param fields the fields to retrieve. 493 * @return info about this item containing only the specified fields, including representations. 494 */ 495 public BoxFile.Info getInfoWithRepresentations(String representationHints, String... fields) { 496 if (representationHints.matches(Representation.X_REP_HINTS_PATTERN)) { 497 //Since the user intends to get representations, add it to fields, even if user has missed it 498 Set<String> fieldsSet = new HashSet<String>(Arrays.asList(fields)); 499 fieldsSet.add("representations"); 500 String queryString = new QueryStringBuilder().appendParam("fields", 501 fieldsSet.toArray(new String[fieldsSet.size()])).toString(); 502 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 503 504 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 505 request.addHeader("X-Rep-Hints", representationHints); 506 BoxJSONResponse response = (BoxJSONResponse) request.send(); 507 return new Info(response.getJSON()); 508 } else { 509 throw new BoxAPIException("Represention hints is not valid." 510 + " Refer documention on how to construct X-Rep-Hints Header"); 511 } 512 } 513 514 /** 515 * Fetches the contents of a file representation and writes them to the provided output stream. 516 * @see <a href=https://developer.box.com/reference#section-x-rep-hints-header>X-Rep-Hints Header</a> 517 * @param representationHint the X-Rep-Hints query for the representation to fetch. 518 * @param output the output stream to write the contents to. 519 */ 520 public void getRepresentationContent(String representationHint, OutputStream output) { 521 522 this.getRepresentationContent(representationHint, "", output); 523 } 524 525 /** 526 * Fetches the contents of a file representation with asset path and writes them to the provided output stream. 527 * @see <a href=https://developer.box.com/reference#section-x-rep-hints-header>X-Rep-Hints Header</a> 528 * @param representationHint the X-Rep-Hints query for the representation to fetch. 529 * @param assetPath the path of the asset for representations containing multiple files. 530 * @param output the output stream to write the contents to. 531 */ 532 public void getRepresentationContent(String representationHint, String assetPath, OutputStream output) { 533 534 List<Representation> reps = this.getInfoWithRepresentations(representationHint).getRepresentations(); 535 if (reps.size() < 1) { 536 throw new BoxAPIException("No matching representations found"); 537 } 538 Representation representation = reps.get(0); 539 String repState = representation.getStatus().getState(); 540 541 if (repState.equals("viewable") || repState.equals("success")) { 542 543 this.makeRepresentationContentRequest(representation.getContent().getUrlTemplate(), 544 assetPath, output); 545 return; 546 } else if (repState.equals("pending") || repState.equals("none")) { 547 548 String repContentURLString = null; 549 while (repContentURLString == null) { 550 repContentURLString = this.pollRepInfo(representation.getInfo().getUrl()); 551 } 552 553 this.makeRepresentationContentRequest(repContentURLString, assetPath, output); 554 return; 555 556 } else if (repState.equals("error")) { 557 558 throw new BoxAPIException("Representation had error status"); 559 } else { 560 561 throw new BoxAPIException("Representation had unknown status"); 562 } 563 564 } 565 566 private String pollRepInfo(URL infoURL) { 567 568 BoxAPIRequest infoRequest = new BoxAPIRequest(this.getAPI(), infoURL, HttpMethod.GET); 569 BoxJSONResponse infoResponse = (BoxJSONResponse) infoRequest.send(); 570 JsonObject response = infoResponse.getJsonObject(); 571 572 Representation rep = new Representation(response); 573 574 String repState = rep.getStatus().getState(); 575 576 if (repState.equals("viewable") || repState.equals("success")) { 577 578 return rep.getContent().getUrlTemplate(); 579 } else if (repState.equals("pending") || repState.equals("none")) { 580 581 return null; 582 583 } else if (repState.equals("error")) { 584 585 throw new BoxAPIException("Representation had error status"); 586 } else { 587 588 throw new BoxAPIException("Representation had unknown status"); 589 } 590 } 591 592 private void makeRepresentationContentRequest(String representationURLTemplate, String assetPath, 593 OutputStream output) { 594 595 try { 596 597 URL repURL = new URL(representationURLTemplate.replace("{+asset_path}", assetPath)); 598 BoxAPIRequest repContentReq = new BoxAPIRequest(this.getAPI(), repURL, HttpMethod.GET); 599 600 BoxAPIResponse contentResponse = repContentReq.send(); 601 602 InputStream input = contentResponse.getBody(); 603 604 byte[] buffer = new byte[BUFFER_SIZE]; 605 try { 606 int n = input.read(buffer); 607 while (n != -1) { 608 output.write(buffer, 0, n); 609 n = input.read(buffer); 610 } 611 } catch (IOException e) { 612 throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); 613 } finally { 614 contentResponse.disconnect(); 615 } 616 } catch (MalformedURLException ex) { 617 618 throw new BoxAPIException("Could not generate representation content URL"); 619 } 620 } 621 622 /** 623 * Updates the information about this file with any info fields that have been modified locally. 624 * 625 * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following 626 * code won't update any information (or even send a network request) since none of the info's fields were 627 * changed:</p> 628 * 629 * <pre>BoxFile file = new File(api, id); 630 * BoxFile.Info info = file.getInfo(); 631 * file.updateInfo(info);</pre> 632 * 633 * @param info the updated info. 634 */ 635 public void updateInfo(BoxFile.Info info) { 636 URL url = FILE_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 637 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 638 request.setBody(info.getPendingChanges()); 639 BoxJSONResponse response = (BoxJSONResponse) request.send(); 640 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 641 info.update(jsonObject); 642 } 643 644 /** 645 * Gets any previous versions of this file. Note that only users with premium accounts will be able to retrieve 646 * previous versions of their files. 647 * 648 * @return a list of previous file versions. 649 */ 650 public Collection<BoxFileVersion> getVersions() { 651 URL url = VERSIONS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 652 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 653 BoxJSONResponse response = (BoxJSONResponse) request.send(); 654 655 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 656 JsonArray entries = jsonObject.get("entries").asArray(); 657 Collection<BoxFileVersion> versions = new ArrayList<BoxFileVersion>(); 658 for (JsonValue entry : entries) { 659 versions.add(new BoxFileVersion(this.getAPI(), entry.asObject(), this.getID())); 660 } 661 662 return versions; 663 } 664 665 /** 666 * Checks if the file can be successfully uploaded by using the preflight check. 667 * 668 * @param name the name to give the uploaded file or null to use existing name. 669 * @param fileSize the size of the file used for account capacity calculations. 670 * @param parentID the ID of the parent folder that the new version is being uploaded to. 671 * @deprecated This method will be removed in future versions of the SDK; use canUploadVersion(String, long) instead 672 */ 673 @Deprecated 674 public void canUploadVersion(String name, long fileSize, String parentID) { 675 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 676 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 677 678 JsonObject parent = new JsonObject(); 679 parent.add("id", parentID); 680 681 JsonObject preflightInfo = new JsonObject(); 682 preflightInfo.add("parent", parent); 683 if (name != null) { 684 preflightInfo.add("name", name); 685 } 686 687 preflightInfo.add("size", fileSize); 688 689 request.setBody(preflightInfo.toString()); 690 BoxAPIResponse response = request.send(); 691 response.disconnect(); 692 } 693 694 /** 695 * Checks if a new version of the file can be uploaded with the specified name. 696 * @param name the new name for the file. 697 * @return whether or not the file version can be uploaded. 698 */ 699 public boolean canUploadVersion(String name) { 700 return this.canUploadVersion(name, 0); 701 } 702 703 /** 704 * Checks if a new version of the file can be uploaded with the specified name and size. 705 * @param name the new name for the file. 706 * @param fileSize the size of the new version content in bytes. 707 * @return whether or not the file version can be uploaded. 708 */ 709 public boolean canUploadVersion(String name, long fileSize) { 710 711 URL url = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 712 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 713 714 JsonObject preflightInfo = new JsonObject(); 715 if (name != null) { 716 preflightInfo.add("name", name); 717 } 718 719 preflightInfo.add("size", fileSize); 720 721 request.setBody(preflightInfo.toString()); 722 try { 723 BoxAPIResponse response = request.send(); 724 725 return response.getResponseCode() == 200; 726 } catch (BoxAPIException ex) { 727 728 if (ex.getResponseCode() >= 400 && ex.getResponseCode() < 500) { 729 // This looks like an error response, meaning the upload would fail 730 return false; 731 } else { 732 // This looks like a network error or server error, rethrow exception 733 throw ex; 734 } 735 } 736 } 737 738 /** 739 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 740 * will be able to view and recover previous versions of the file. 741 * 742 * @param fileContent a stream containing the new file contents. 743 * @deprecated use uploadNewVersion() instead. 744 */ 745 @Deprecated 746 public void uploadVersion(InputStream fileContent) { 747 this.uploadVersion(fileContent, null); 748 } 749 750 /** 751 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 752 * will be able to view and recover previous versions of the file. 753 * 754 * @param fileContent a stream containing the new file contents. 755 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 756 * @deprecated use uploadNewVersion() instead. 757 */ 758 @Deprecated 759 public void uploadVersion(InputStream fileContent, String fileContentSHA1) { 760 this.uploadVersion(fileContent, fileContentSHA1, null); 761 } 762 763 /** 764 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 765 * will be able to view and recover previous versions of the file. 766 * 767 * @param fileContent a stream containing the new file contents. 768 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 769 * @param modified the date that the new version was modified. 770 * @deprecated use uploadNewVersion() instead. 771 */ 772 @Deprecated 773 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 774 this.uploadVersion(fileContent, fileContentSHA1, modified, 0, null); 775 } 776 777 /** 778 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 779 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 780 * of the file. 781 * 782 * @param fileContent a stream containing the new file contents. 783 * @param modified the date that the new version was modified. 784 * @param fileSize the size of the file used for determining the progress of the upload. 785 * @param listener a listener for monitoring the upload's progress. 786 * @deprecated use uploadNewVersion() instead. 787 */ 788 @Deprecated 789 public void uploadVersion(InputStream fileContent, Date modified, long fileSize, ProgressListener listener) { 790 this.uploadVersion(fileContent, null, modified, fileSize, listener); 791 } 792 793 /** 794 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 795 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 796 * of the file. 797 * 798 * @param fileContent a stream containing the new file contents. 799 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 800 * @param modified the date that the new version was modified. 801 * @param fileSize the size of the file used for determining the progress of the upload. 802 * @param listener a listener for monitoring the upload's progress. 803 * @deprecated use uploadNewVersion() instead. 804 */ 805 @Deprecated 806 public void uploadVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 807 ProgressListener listener) { 808 this.uploadNewVersion(fileContent, fileContentSHA1, modified, fileSize, listener); 809 return; 810 } 811 812 /** 813 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 814 * will be able to view and recover previous versions of the file. 815 * 816 * @param fileContent a stream containing the new file contents. 817 * @return the uploaded file version. 818 */ 819 public BoxFile.Info uploadNewVersion(InputStream fileContent) { 820 return this.uploadNewVersion(fileContent, null); 821 } 822 823 /** 824 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 825 * will be able to view and recover previous versions of the file. 826 * 827 * @param fileContent a stream containing the new file contents. 828 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 829 * @return the uploaded file version. 830 */ 831 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1) { 832 return this.uploadNewVersion(fileContent, fileContentSHA1, null); 833 } 834 835 /** 836 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 837 * will be able to view and recover previous versions of the file. 838 * 839 * @param fileContent a stream containing the new file contents. 840 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 841 * @param modified the date that the new version was modified. 842 * @return the uploaded file version. 843 */ 844 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified) { 845 return this.uploadNewVersion(fileContent, fileContentSHA1, modified, 0, null); 846 } 847 848 /** 849 * Uploads a new version of this file, replacing the current version. Note that only users with premium accounts 850 * will be able to view and recover previous versions of the file. 851 * 852 * @param fileContent a stream containing the new file contents. 853 * @param fileContentSHA1 a string containing the SHA1 hash of the new file contents. 854 * @param modified the date that the new version was modified. 855 * @param name the new name for the file 856 * @return the uploaded file version. 857 */ 858 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified, String name) { 859 return this.uploadNewVersion(fileContent, fileContentSHA1, modified, name, 0, null); 860 } 861 862 /** 863 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 864 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 865 * of the file. 866 * 867 * @param fileContent a stream containing the new file contents. 868 * @param modified the date that the new version was modified. 869 * @param fileSize the size of the file used for determining the progress of the upload. 870 * @param listener a listener for monitoring the upload's progress. 871 * @return the uploaded file version. 872 */ 873 public BoxFile.Info uploadNewVersion(InputStream fileContent, Date modified, long fileSize, 874 ProgressListener listener) { 875 return this.uploadNewVersion(fileContent, null, modified, fileSize, listener); 876 } 877 878 /** 879 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 880 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 881 * of the file. 882 * 883 * @param fileContent a stream containing the new file contents. 884 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 885 * @param modified the date that the new version was modified. 886 * @param fileSize the size of the file used for determining the progress of the upload. 887 * @param listener a listener for monitoring the upload's progress. 888 * @return the uploaded file version. 889 */ 890 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified, long fileSize, 891 ProgressListener listener) { 892 return this.uploadNewVersion(fileContent, fileContentSHA1, modified, null, fileSize, listener); 893 } 894 895 /** 896 * Uploads a new version of this file, replacing the current version, while reporting the progress to a 897 * ProgressListener. Note that only users with premium accounts will be able to view and recover previous versions 898 * of the file. 899 * 900 * @param fileContent a stream containing the new file contents. 901 * @param fileContentSHA1 the SHA1 hash of the file contents. will be sent along in the Content-MD5 header 902 * @param modified the date that the new version was modified. 903 * @param name the new name for the file 904 * @param fileSize the size of the file used for determining the progress of the upload. 905 * @param listener a listener for monitoring the upload's progress. 906 * @return the uploaded file version. 907 */ 908 public BoxFile.Info uploadNewVersion(InputStream fileContent, String fileContentSHA1, Date modified, String name, 909 long fileSize, ProgressListener listener) { 910 URL uploadURL = CONTENT_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 911 BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL); 912 913 if (fileSize > 0) { 914 request.setFile(fileContent, "", fileSize); 915 } else { 916 request.setFile(fileContent, ""); 917 } 918 919 if (fileContentSHA1 != null) { 920 request.setContentSHA1(fileContentSHA1); 921 } 922 923 JsonObject attributesJSON = new JsonObject(); 924 if (modified != null) { 925 attributesJSON.add("content_modified_at", BoxDateFormat.format(modified)); 926 } 927 928 if (name != null) { 929 attributesJSON.add("name", name); 930 } 931 932 request.putField("attributes", attributesJSON.toString()); 933 934 BoxJSONResponse response; 935 if (listener == null) { 936 response = (BoxJSONResponse) request.send(); 937 } else { 938 response = (BoxJSONResponse) request.send(listener); 939 } 940 941 String fileJSON = response.getJsonObject().get("entries").asArray().get(0).toString(); 942 943 return new BoxFile.Info(fileJSON); 944 } 945 946 /** 947 * Gets an expiring URL for creating an embedded preview session. The URL will expire after 60 seconds and the 948 * preview session will expire after 60 minutes. 949 * 950 * @return the expiring preview link 951 */ 952 public URL getPreviewLink() { 953 BoxFile.Info info = this.getInfo("expiring_embed_link"); 954 955 return info.getPreviewLink(); 956 } 957 958 959 /** 960 * Retrieves a thumbnail, or smaller image representation, of this file. Sizes of 32x32, 64x64, 128x128, 961 * and 256x256 can be returned in the .png format and sizes of 32x32, 94x94, 160x160, and 320x320 can be returned 962 * in the .jpg format. 963 * 964 * @param fileType either PNG of JPG 965 * @param minWidth minimum width 966 * @param minHeight minimum height 967 * @param maxWidth maximum width 968 * @param maxHeight maximum height 969 * @return the byte array of the thumbnail image 970 * @deprecated use getRepresentationContent() instead 971 */ 972 @Deprecated 973 public byte[] getThumbnail(ThumbnailFileType fileType, int minWidth, int minHeight, int maxWidth, int maxHeight) { 974 QueryStringBuilder builder = new QueryStringBuilder(); 975 builder.appendParam("min_width", minWidth); 976 builder.appendParam("min_height", minHeight); 977 builder.appendParam("max_width", maxWidth); 978 builder.appendParam("max_height", maxHeight); 979 980 URLTemplate template; 981 if (fileType == ThumbnailFileType.PNG) { 982 template = GET_THUMBNAIL_PNG_TEMPLATE; 983 } else if (fileType == ThumbnailFileType.JPG) { 984 template = GET_THUMBNAIL_JPG_TEMPLATE; 985 } else { 986 throw new BoxAPIException("Unsupported thumbnail file type"); 987 } 988 URL url = template.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID()); 989 990 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 991 BoxAPIResponse response = request.send(); 992 993 ByteArrayOutputStream thumbOut = new ByteArrayOutputStream(); 994 InputStream body = response.getBody(); 995 byte[] buffer = new byte[BUFFER_SIZE]; 996 try { 997 int n = body.read(buffer); 998 while (n != -1) { 999 thumbOut.write(buffer, 0, n); 1000 n = body.read(buffer); 1001 } 1002 } catch (IOException e) { 1003 throw new BoxAPIException("Error reading thumbnail bytes from response body", e); 1004 } finally { 1005 response.disconnect(); 1006 } 1007 1008 return thumbOut.toByteArray(); 1009 } 1010 1011 /** 1012 * Gets a list of any comments on this file. 1013 * 1014 * @return a list of comments on this file. 1015 */ 1016 public List<BoxComment.Info> getComments() { 1017 URL url = GET_COMMENTS_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 1018 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 1019 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1020 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 1021 1022 int totalCount = responseJSON.get("total_count").asInt(); 1023 List<BoxComment.Info> comments = new ArrayList<BoxComment.Info>(totalCount); 1024 JsonArray entries = responseJSON.get("entries").asArray(); 1025 for (JsonValue value : entries) { 1026 JsonObject commentJSON = value.asObject(); 1027 BoxComment comment = new BoxComment(this.getAPI(), commentJSON.get("id").asString()); 1028 BoxComment.Info info = comment.new Info(commentJSON); 1029 comments.add(info); 1030 } 1031 1032 return comments; 1033 } 1034 1035 /** 1036 * Gets a list of any tasks on this file with requested fields. 1037 * 1038 * @param fields optional fields to retrieve for this task. 1039 * @return a list of tasks on this file. 1040 */ 1041 public List<BoxTask.Info> getTasks(String... fields) { 1042 QueryStringBuilder builder = new QueryStringBuilder(); 1043 if (fields.length > 0) { 1044 builder.appendParam("fields", fields).toString(); 1045 } 1046 URL url = GET_TASKS_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID()); 1047 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 1048 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1049 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 1050 1051 int totalCount = responseJSON.get("total_count").asInt(); 1052 List<BoxTask.Info> tasks = new ArrayList<BoxTask.Info>(totalCount); 1053 JsonArray entries = responseJSON.get("entries").asArray(); 1054 for (JsonValue value : entries) { 1055 JsonObject taskJSON = value.asObject(); 1056 BoxTask task = new BoxTask(this.getAPI(), taskJSON.get("id").asString()); 1057 BoxTask.Info info = task.new Info(taskJSON); 1058 tasks.add(info); 1059 } 1060 1061 return tasks; 1062 } 1063 1064 /** 1065 * Creates metadata on this file in the global properties template. 1066 * 1067 * @param metadata The new metadata values. 1068 * @return the metadata returned from the server. 1069 */ 1070 public Metadata createMetadata(Metadata metadata) { 1071 return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata); 1072 } 1073 1074 /** 1075 * Creates metadata on this file in the specified template type. 1076 * 1077 * @param typeName the metadata template type name. 1078 * @param metadata the new metadata values. 1079 * @return the metadata returned from the server. 1080 */ 1081 public Metadata createMetadata(String typeName, Metadata metadata) { 1082 String scope = Metadata.scopeBasedOnType(typeName); 1083 return this.createMetadata(typeName, scope, metadata); 1084 } 1085 1086 /** 1087 * Creates metadata on this file in the specified template type. 1088 * 1089 * @param typeName the metadata template type name. 1090 * @param scope the metadata scope (global or enterprise). 1091 * @param metadata the new metadata values. 1092 * @return the metadata returned from the server. 1093 */ 1094 public Metadata createMetadata(String typeName, String scope, Metadata metadata) { 1095 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1096 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST"); 1097 request.addHeader("Content-Type", "application/json"); 1098 request.setBody(metadata.toString()); 1099 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1100 return new Metadata(JsonObject.readFrom(response.getJSON())); 1101 } 1102 1103 /** 1104 * Sets the provided metadata on the file, overwriting any existing metadata keys already present. 1105 * 1106 * @param templateName the name of the metadata template. 1107 * @param scope the scope of the template (usually "global" or "enterprise"). 1108 * @param metadata the new metadata values. 1109 * @return the metadata returned from the server. 1110 */ 1111 public Metadata setMetadata(String templateName, String scope, Metadata metadata) { 1112 Metadata metadataValue = null; 1113 1114 try { 1115 metadataValue = this.createMetadata(templateName, scope, metadata); 1116 } catch (BoxAPIException e) { 1117 if (e.getResponseCode() == 409) { 1118 Metadata metadataToUpdate = new Metadata(scope, templateName); 1119 for (JsonValue value : metadata.getOperations()) { 1120 if (value.asObject().get("value").isNumber()) { 1121 metadataToUpdate.add(value.asObject().get("path").asString(), 1122 value.asObject().get("value").asDouble()); 1123 } else if (value.asObject().get("value").isString()) { 1124 metadataToUpdate.add(value.asObject().get("path").asString(), 1125 value.asObject().get("value").asString()); 1126 } else if (value.asObject().get("value").isArray()) { 1127 ArrayList<String> list = new ArrayList<String>(); 1128 for (JsonValue jsonValue : value.asObject().get("value").asArray()) { 1129 list.add(jsonValue.asString()); 1130 } 1131 metadataToUpdate.add(value.asObject().get("path").asString(), list); 1132 } 1133 } 1134 metadataValue = this.updateMetadata(metadataToUpdate); 1135 } else { 1136 throw e; 1137 } 1138 } 1139 1140 return metadataValue; 1141 } 1142 1143 /** 1144 * Adds a metadata classification to the specified file. 1145 * 1146 * @param classificationType the metadata classification type. 1147 * @return the metadata classification type added to the file. 1148 */ 1149 public String addClassification(String classificationType) { 1150 Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType); 1151 Metadata classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, 1152 "enterprise", metadata); 1153 1154 return classification.getString(Metadata.CLASSIFICATION_KEY); 1155 } 1156 1157 /** 1158 * Updates a metadata classification on the specified file. 1159 * 1160 * @param classificationType the metadata classification type. 1161 * @return the new metadata classification type updated on the file. 1162 */ 1163 public String updateClassification(String classificationType) { 1164 Metadata metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY); 1165 metadata.add("/Box__Security__Classification__Key", classificationType); 1166 Metadata classification = this.updateMetadata(metadata); 1167 1168 return classification.getString(Metadata.CLASSIFICATION_KEY); 1169 } 1170 1171 /** 1172 * Attempts to add classification to a file. If classification already exists then do update. 1173 * 1174 * @param classificationType the metadata classification type. 1175 * @return the metadata classification type on the file. 1176 */ 1177 public String setClassification(String classificationType) { 1178 Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType); 1179 Metadata classification = null; 1180 1181 try { 1182 classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise", metadata); 1183 } catch (BoxAPIException e) { 1184 if (e.getResponseCode() == 409) { 1185 metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY); 1186 metadata.replace(Metadata.CLASSIFICATION_KEY, classificationType); 1187 classification = this.updateMetadata(metadata); 1188 } else { 1189 throw e; 1190 } 1191 } 1192 1193 return classification.getString(Metadata.CLASSIFICATION_KEY); 1194 } 1195 1196 /** 1197 * Gets the classification type for the specified file. 1198 * 1199 * @return the metadata classification type on the file. 1200 */ 1201 public String getClassification() { 1202 Metadata metadata; 1203 try { 1204 metadata = this.getMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY); 1205 1206 } catch (BoxAPIException e) { 1207 JsonObject responseObject = JsonObject.readFrom(e.getResponse()); 1208 String code = responseObject.get("code").asString(); 1209 1210 if (e.getResponseCode() == 404 && code.equals("instance_not_found")) { 1211 return null; 1212 } else { 1213 throw e; 1214 } 1215 } 1216 1217 return metadata.getString(Metadata.CLASSIFICATION_KEY); 1218 } 1219 1220 /** 1221 * Deletes the classification on the file. 1222 */ 1223 public void deleteClassification() { 1224 this.deleteMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise"); 1225 } 1226 1227 /** 1228 * Locks a file. 1229 * 1230 * @return the lock returned from the server. 1231 */ 1232 public BoxLock lock() { 1233 return this.lock(null, false); 1234 } 1235 1236 /** 1237 * Locks a file. 1238 * 1239 * @param isDownloadPrevented is downloading of file prevented when locked. 1240 * @return the lock returned from the server. 1241 */ 1242 public BoxLock lock(boolean isDownloadPrevented) { 1243 return this.lock(null, isDownloadPrevented); 1244 } 1245 1246 /** 1247 * Locks a file. 1248 * 1249 * @param expiresAt expiration date of the lock. 1250 * @return the lock returned from the server. 1251 */ 1252 public BoxLock lock(Date expiresAt) { 1253 return this.lock(expiresAt, false); 1254 } 1255 1256 /** 1257 * Locks a file. 1258 * 1259 * @param expiresAt expiration date of the lock. 1260 * @param isDownloadPrevented is downloading of file prevented when locked. 1261 * @return the lock returned from the server. 1262 */ 1263 public BoxLock lock(Date expiresAt, boolean isDownloadPrevented) { 1264 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 1265 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 1266 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 1267 1268 JsonObject lockConfig = new JsonObject(); 1269 lockConfig.add("type", "lock"); 1270 if (expiresAt != null) { 1271 lockConfig.add("expires_at", BoxDateFormat.format(expiresAt)); 1272 } 1273 lockConfig.add("is_download_prevented", isDownloadPrevented); 1274 1275 JsonObject requestJSON = new JsonObject(); 1276 requestJSON.add("lock", lockConfig); 1277 request.setBody(requestJSON.toString()); 1278 1279 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1280 1281 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 1282 JsonValue lockValue = responseJSON.get("lock"); 1283 JsonObject lockJSON = JsonObject.readFrom(lockValue.toString()); 1284 1285 return new BoxLock(lockJSON, this.getAPI()); 1286 } 1287 1288 /** 1289 * Unlocks a file. 1290 */ 1291 public void unlock() { 1292 String queryString = new QueryStringBuilder().appendParam("fields", "lock").toString(); 1293 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 1294 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 1295 1296 JsonObject lockObject = new JsonObject(); 1297 lockObject.add("lock", JsonObject.NULL); 1298 1299 request.setBody(lockObject.toString()); 1300 request.send(); 1301 } 1302 1303 /** 1304 * Used to retrieve all metadata associated with the file. 1305 * 1306 * @param fields the optional fields to retrieve. 1307 * @return An iterable of metadata instances associated with the file. 1308 */ 1309 public Iterable<Metadata> getAllMetadata(String... fields) { 1310 return Metadata.getAllMetadata(this, fields); 1311 } 1312 1313 /** 1314 * Gets the file properties metadata. 1315 * 1316 * @return the metadata returned from the server. 1317 */ 1318 public Metadata getMetadata() { 1319 return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE); 1320 } 1321 1322 /** 1323 * Gets the file metadata of specified template type. 1324 * 1325 * @param typeName the metadata template type name. 1326 * @return the metadata returned from the server. 1327 */ 1328 public Metadata getMetadata(String typeName) { 1329 String scope = Metadata.scopeBasedOnType(typeName); 1330 return this.getMetadata(typeName, scope); 1331 } 1332 1333 /** 1334 * Gets the file metadata of specified template type. 1335 * 1336 * @param typeName the metadata template type name. 1337 * @param scope the metadata scope (global or enterprise). 1338 * @return the metadata returned from the server. 1339 */ 1340 public Metadata getMetadata(String typeName, String scope) { 1341 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1342 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 1343 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1344 return new Metadata(JsonObject.readFrom(response.getJSON())); 1345 } 1346 1347 /** 1348 * Updates the file metadata. 1349 * 1350 * @param metadata the new metadata values. 1351 * @return the metadata returned from the server. 1352 */ 1353 public Metadata updateMetadata(Metadata metadata) { 1354 String scope; 1355 if (metadata.getScope().equals(Metadata.GLOBAL_METADATA_SCOPE)) { 1356 scope = Metadata.GLOBAL_METADATA_SCOPE; 1357 } else if (metadata.getScope().startsWith(Metadata.ENTERPRISE_METADATA_SCOPE)) { 1358 scope = metadata.getScope(); 1359 } else { 1360 scope = Metadata.ENTERPRISE_METADATA_SCOPE; 1361 } 1362 1363 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), 1364 scope, metadata.getTemplateName()); 1365 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 1366 request.addHeader("Content-Type", "application/json-patch+json"); 1367 request.setBody(metadata.getPatch()); 1368 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1369 return new Metadata(JsonObject.readFrom(response.getJSON())); 1370 } 1371 1372 /** 1373 * Deletes the file properties metadata. 1374 */ 1375 public void deleteMetadata() { 1376 this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE); 1377 } 1378 1379 /** 1380 * Deletes the file metadata of specified template type. 1381 * 1382 * @param typeName the metadata template type name. 1383 */ 1384 public void deleteMetadata(String typeName) { 1385 String scope = Metadata.scopeBasedOnType(typeName); 1386 this.deleteMetadata(typeName, scope); 1387 } 1388 1389 /** 1390 * Deletes the file metadata of specified template type. 1391 * 1392 * @param typeName the metadata template type name. 1393 * @param scope the metadata scope (global or enterprise). 1394 */ 1395 public void deleteMetadata(String typeName, String scope) { 1396 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, typeName); 1397 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 1398 request.send(); 1399 } 1400 1401 /** 1402 * Used to retrieve the watermark for the file. 1403 * If the file does not have a watermark applied to it, a 404 Not Found will be returned by API. 1404 * 1405 * @param fields the fields to retrieve. 1406 * @return the watermark associated with the file. 1407 */ 1408 public BoxWatermark getWatermark(String... fields) { 1409 return this.getWatermark(FILE_URL_TEMPLATE, fields); 1410 } 1411 1412 /** 1413 * Used to apply or update the watermark for the file. 1414 * 1415 * @return the watermark associated with the file. 1416 */ 1417 public BoxWatermark applyWatermark() { 1418 return this.applyWatermark(FILE_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT); 1419 } 1420 1421 /** 1422 * Removes a watermark from the file. 1423 * If the file did not have a watermark applied to it, a 404 Not Found will be returned by API. 1424 */ 1425 public void removeWatermark() { 1426 this.removeWatermark(FILE_URL_TEMPLATE); 1427 } 1428 1429 /** 1430 * {@inheritDoc} 1431 */ 1432 @Override 1433 public BoxFile.Info setCollections(BoxCollection... collections) { 1434 JsonArray jsonArray = new JsonArray(); 1435 for (BoxCollection collection : collections) { 1436 JsonObject collectionJSON = new JsonObject(); 1437 collectionJSON.add("id", collection.getID()); 1438 jsonArray.add(collectionJSON); 1439 } 1440 JsonObject infoJSON = new JsonObject(); 1441 infoJSON.add("collections", jsonArray); 1442 1443 String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString(); 1444 URL url = FILE_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 1445 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 1446 request.setBody(infoJSON.toString()); 1447 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1448 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1449 return new Info(jsonObject); 1450 } 1451 1452 /** 1453 * Creates an upload session to create a new version of a file in chunks. 1454 * This will first verify that the version can be created and then open a session for uploading pieces of the file. 1455 * @param fileSize the size of the file that will be uploaded. 1456 * @return the created upload session instance. 1457 */ 1458 public BoxFileUploadSession.Info createUploadSession(long fileSize) { 1459 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1460 1461 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 1462 request.addHeader("Content-Type", "application/json"); 1463 1464 JsonObject body = new JsonObject(); 1465 body.add("file_size", fileSize); 1466 request.setBody(body.toString()); 1467 1468 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1469 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 1470 1471 String sessionId = jsonObject.get("id").asString(); 1472 BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId); 1473 return session.new Info(jsonObject); 1474 } 1475 1476 /** 1477 * Creates a new version of a file. 1478 * @param inputStream the stream instance that contains the data. 1479 * @param fileSize the size of the file that will be uploaded. 1480 * @return the created file instance. 1481 * @throws InterruptedException when a thread execution is interrupted. 1482 * @throws IOException when reading a stream throws exception. 1483 */ 1484 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize) 1485 throws InterruptedException, IOException { 1486 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1487 return new LargeFileUpload().upload(this.getAPI(), inputStream, url, fileSize); 1488 } 1489 1490 /** 1491 * Creates a new version of a file. Also sets file attributes. 1492 * @param inputStream the stream instance that contains the data. 1493 * @param fileSize the size of the file that will be uploaded. 1494 * @param fileAttributes file attributes to set 1495 * @return the created file instance. 1496 * @throws InterruptedException when a thread execution is interrupted. 1497 * @throws IOException when reading a stream throws exception. 1498 */ 1499 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize, Map<String, String> fileAttributes) 1500 throws InterruptedException, IOException { 1501 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1502 return new LargeFileUpload().upload(this.getAPI(), inputStream, url, fileSize, fileAttributes); 1503 } 1504 1505 /** 1506 * Creates a new version of a file using specified number of parallel http connections. 1507 * @param inputStream the stream instance that contains the data. 1508 * @param fileSize the size of the file that will be uploaded. 1509 * @param nParallelConnections number of parallel http connections to use 1510 * @param timeOut time to wait before killing the job 1511 * @param unit time unit for the time wait value 1512 * @return the created file instance. 1513 * @throws InterruptedException when a thread execution is interrupted. 1514 * @throws IOException when reading a stream throws exception. 1515 */ 1516 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize, 1517 int nParallelConnections, long timeOut, TimeUnit unit) 1518 throws InterruptedException, IOException { 1519 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1520 return new LargeFileUpload(nParallelConnections, timeOut, unit) 1521 .upload(this.getAPI(), inputStream, url, fileSize); 1522 } 1523 1524 /** 1525 * Creates a new version of a file using specified number of parallel http connections. Also sets file attributes. 1526 * @param inputStream the stream instance that contains the data. 1527 * @param fileSize the size of the file that will be uploaded. 1528 * @param nParallelConnections number of parallel http connections to use 1529 * @param timeOut time to wait before killing the job 1530 * @param unit time unit for the time wait value 1531 * @param fileAttributes file attributes to set 1532 * @return the created file instance. 1533 * @throws InterruptedException when a thread execution is interrupted. 1534 * @throws IOException when reading a stream throws exception. 1535 */ 1536 public BoxFile.Info uploadLargeFile(InputStream inputStream, long fileSize, 1537 int nParallelConnections, long timeOut, TimeUnit unit, 1538 Map<String, String> fileAttributes) 1539 throws InterruptedException, IOException { 1540 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL(), this.getID()); 1541 return new LargeFileUpload(nParallelConnections, timeOut, unit) 1542 .upload(this.getAPI(), inputStream, url, fileSize, fileAttributes); 1543 } 1544 1545 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role, 1546 Boolean notify, Boolean canViewPath) { 1547 1548 JsonObject itemField = new JsonObject(); 1549 itemField.add("id", this.getID()); 1550 itemField.add("type", "file"); 1551 1552 return BoxCollaboration.create(this.getAPI(), accessibleByField, itemField, role, notify, canViewPath); 1553 } 1554 1555 /** 1556 * Adds a collaborator to this file. 1557 * 1558 * @param collaborator the collaborator to add. 1559 * @param role the role of the collaborator. 1560 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1561 * @param canViewPath whether view path collaboration feature is enabled or not. 1562 * @return info about the new collaboration. 1563 */ 1564 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role, 1565 Boolean notify, Boolean canViewPath) { 1566 JsonObject accessibleByField = new JsonObject(); 1567 accessibleByField.add("id", collaborator.getID()); 1568 1569 if (collaborator instanceof BoxUser) { 1570 accessibleByField.add("type", "user"); 1571 } else if (collaborator instanceof BoxGroup) { 1572 accessibleByField.add("type", "group"); 1573 } else { 1574 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 1575 } 1576 return this.collaborate(accessibleByField, role, notify, canViewPath); 1577 } 1578 1579 1580 /** 1581 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 1582 * account. 1583 * 1584 * @param email the email address of the collaborator to add. 1585 * @param role the role of the collaborator. 1586 * @param notify determines if the user (or all the users in the group) will receive email notifications. 1587 * @param canViewPath whether view path collaboration feature is enabled or not. 1588 * @return info about the new collaboration. 1589 */ 1590 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role, 1591 Boolean notify, Boolean canViewPath) { 1592 JsonObject accessibleByField = new JsonObject(); 1593 accessibleByField.add("login", email); 1594 accessibleByField.add("type", "user"); 1595 1596 return this.collaborate(accessibleByField, role, notify, canViewPath); 1597 } 1598 1599 /** 1600 * Used to retrieve all collaborations associated with the item. 1601 * 1602 * @param fields the optional fields to retrieve. 1603 * @return An iterable of metadata instances associated with the item. 1604 */ 1605 public BoxResourceIterable<BoxCollaboration.Info> getAllFileCollaborations(String... fields) { 1606 return BoxCollaboration.getAllFileCollaborations(this.getAPI(), this.getID(), 1607 GET_COLLABORATORS_PAGE_SIZE, fields); 1608 1609 } 1610 1611 /** 1612 * Contains information about a BoxFile. 1613 */ 1614 public class Info extends BoxItem.Info { 1615 private String sha1; 1616 private String versionNumber; 1617 private long commentCount; 1618 private EnumSet<Permission> permissions; 1619 private String extension; 1620 private boolean isPackage; 1621 private BoxFileVersion version; 1622 private URL previewLink; 1623 private BoxLock lock; 1624 private boolean isWatermarked; 1625 private boolean isExternallyOwned; 1626 private JsonObject metadata; 1627 private Map<String, Map<String, Metadata>> metadataMap; 1628 private List<Representation> representations; 1629 private List<String> allowedInviteeRoles; 1630 private Boolean hasCollaborations; 1631 private String uploaderDisplayName; 1632 private BoxClassification classification; 1633 1634 /** 1635 * Constructs an empty Info object. 1636 */ 1637 public Info() { 1638 super(); 1639 } 1640 1641 /** 1642 * Constructs an Info object by parsing information from a JSON string. 1643 * 1644 * @param json the JSON string to parse. 1645 */ 1646 public Info(String json) { 1647 super(json); 1648 } 1649 1650 /** 1651 * Constructs an Info object using an already parsed JSON object. 1652 * 1653 * @param jsonObject the parsed JSON object. 1654 */ 1655 public Info(JsonObject jsonObject) { 1656 super(jsonObject); 1657 } 1658 1659 @Override 1660 public BoxFile getResource() { 1661 return BoxFile.this; 1662 } 1663 1664 /** 1665 * Gets the SHA1 hash of the file. 1666 * 1667 * @return the SHA1 hash of the file. 1668 */ 1669 public String getSha1() { 1670 return this.sha1; 1671 } 1672 1673 /** 1674 * Gets the lock of the file. 1675 * 1676 * @return the lock of the file. 1677 */ 1678 public BoxLock getLock() { 1679 return this.lock; 1680 } 1681 1682 /** 1683 * Gets the current version number of the file. 1684 * 1685 * @return the current version number of the file. 1686 */ 1687 public String getVersionNumber() { 1688 return this.versionNumber; 1689 } 1690 1691 /** 1692 * Gets the number of comments on the file. 1693 * 1694 * @return the number of comments on the file. 1695 */ 1696 public long getCommentCount() { 1697 return this.commentCount; 1698 } 1699 1700 /** 1701 * Gets the permissions that the current user has on the file. 1702 * 1703 * @return the permissions that the current user has on the file. 1704 */ 1705 public EnumSet<Permission> getPermissions() { 1706 return this.permissions; 1707 } 1708 1709 /** 1710 * Gets the extension suffix of the file, excluding the dot. 1711 * 1712 * @return the extension of the file. 1713 */ 1714 public String getExtension() { 1715 return this.extension; 1716 } 1717 1718 /** 1719 * Gets whether or not the file is an OSX package. 1720 * 1721 * @return true if the file is an OSX package; otherwise false. 1722 */ 1723 public boolean getIsPackage() { 1724 return this.isPackage; 1725 } 1726 1727 /** 1728 * Gets the current version details of the file. 1729 * 1730 * @return the current version details of the file. 1731 */ 1732 public BoxFileVersion getVersion() { 1733 return this.version; 1734 } 1735 1736 /** 1737 * Gets the current expiring preview link. 1738 * 1739 * @return the expiring preview link 1740 */ 1741 public URL getPreviewLink() { 1742 return this.previewLink; 1743 } 1744 1745 /** 1746 * Gets flag indicating whether this file is Watermarked. 1747 * 1748 * @return whether the file is watermarked or not 1749 */ 1750 public boolean getIsWatermarked() { 1751 return this.isWatermarked; 1752 } 1753 1754 /** 1755 * Returns the allowed invitee roles for this file item. 1756 * 1757 * @return the list of roles allowed for invited collaborators. 1758 */ 1759 public List<String> getAllowedInviteeRoles() { 1760 return this.allowedInviteeRoles; 1761 } 1762 1763 /** 1764 * Returns the indicator for whether this file item has collaborations. 1765 * 1766 * @return indicator for whether this file item has collaborations. 1767 */ 1768 public Boolean getHasCollaborations() { 1769 return this.hasCollaborations; 1770 } 1771 1772 /** 1773 * Gets the metadata on this file associated with a specified scope and template. 1774 * Makes an attempt to get metadata that was retrieved using getInfo(String ...) method. If no result is found 1775 * then makes an API call to get metadata 1776 * @param templateName the metadata template type name. 1777 * @param scope the scope of the template (usually "global" or "enterprise"). 1778 * @return the metadata returned from the server. 1779 */ 1780 public Metadata getMetadata(String templateName, String scope) { 1781 try { 1782 return this.metadataMap.get(scope).get(templateName); 1783 } catch (NullPointerException e) { 1784 return null; 1785 } 1786 } 1787 1788 /** 1789 * Returns the field for indicating whether a file is owned by a user outside the enterprise. 1790 * @return indicator for whether or not the file is owned by a user outside the enterprise. 1791 */ 1792 public boolean getIsExternallyOwned() { 1793 return this.isExternallyOwned; 1794 } 1795 1796 /** 1797 * Get file's representations. 1798 * @return list of representations 1799 */ 1800 public List<Representation> getRepresentations() { 1801 return this.representations; 1802 } 1803 1804 /** 1805 * Returns user's name at the time of upload. 1806 * 1807 * @return user's name at the time of upload 1808 */ 1809 public String getUploaderDisplayName() { 1810 return this.uploaderDisplayName; 1811 } 1812 1813 /** 1814 * Gets the metadata classification type of this file. 1815 * @return the metadata classification type of this file. 1816 */ 1817 public BoxClassification getClassification() { 1818 return this.classification; 1819 } 1820 1821 @Override 1822 protected void parseJSONMember(JsonObject.Member member) { 1823 super.parseJSONMember(member); 1824 1825 String memberName = member.getName(); 1826 JsonValue value = member.getValue(); 1827 try { 1828 if (memberName.equals("sha1")) { 1829 this.sha1 = value.asString(); 1830 } else if (memberName.equals("version_number")) { 1831 this.versionNumber = value.asString(); 1832 } else if (memberName.equals("comment_count")) { 1833 this.commentCount = value.asLong(); 1834 } else if (memberName.equals("permissions")) { 1835 this.permissions = this.parsePermissions(value.asObject()); 1836 } else if (memberName.equals("extension")) { 1837 this.extension = value.asString(); 1838 } else if (memberName.equals("is_package")) { 1839 this.isPackage = value.asBoolean(); 1840 } else if (memberName.equals("has_collaborations")) { 1841 this.hasCollaborations = value.asBoolean(); 1842 } else if (memberName.equals("is_externally_owned")) { 1843 this.isExternallyOwned = value.asBoolean(); 1844 } else if (memberName.equals("file_version")) { 1845 this.version = this.parseFileVersion(value.asObject()); 1846 } else if (memberName.equals("allowed_invitee_roles")) { 1847 this.allowedInviteeRoles = this.parseAllowedInviteeRoles(value.asArray()); 1848 } else if (memberName.equals("expiring_embed_link")) { 1849 try { 1850 String urlString = member.getValue().asObject().get("url").asString(); 1851 this.previewLink = new URL(urlString); 1852 } catch (MalformedURLException e) { 1853 throw new BoxAPIException("Couldn't parse expiring_embed_link/url for file", e); 1854 } 1855 } else if (memberName.equals("lock")) { 1856 if (value.isNull()) { 1857 this.lock = null; 1858 } else { 1859 this.lock = new BoxLock(value.asObject(), BoxFile.this.getAPI()); 1860 } 1861 } else if (memberName.equals("watermark_info")) { 1862 JsonObject jsonObject = value.asObject(); 1863 this.isWatermarked = jsonObject.get("is_watermarked").asBoolean(); 1864 } else if (memberName.equals("metadata")) { 1865 JsonObject jsonObject = value.asObject(); 1866 this.metadataMap = Parsers.parseAndPopulateMetadataMap(jsonObject); 1867 } else if (memberName.equals("representations")) { 1868 JsonObject jsonObject = value.asObject(); 1869 this.representations = Parsers.parseRepresentations(jsonObject); 1870 } else if (memberName.equals("uploader_display_name")) { 1871 this.uploaderDisplayName = value.asString(); 1872 } else if (memberName.equals("classification")) { 1873 if (value.isNull()) { 1874 this.classification = null; 1875 } else { 1876 this.classification = new BoxClassification(value.asObject()); 1877 } 1878 } 1879 } catch (Exception e) { 1880 throw new BoxDeserializationException(memberName, value.toString(), e); 1881 } 1882 } 1883 1884 private EnumSet<Permission> parsePermissions(JsonObject jsonObject) { 1885 EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class); 1886 for (JsonObject.Member member : jsonObject) { 1887 JsonValue value = member.getValue(); 1888 if (value.isNull() || !value.asBoolean()) { 1889 continue; 1890 } 1891 1892 String memberName = member.getName(); 1893 if (memberName.equals("can_download")) { 1894 permissions.add(Permission.CAN_DOWNLOAD); 1895 } else if (memberName.equals("can_upload")) { 1896 permissions.add(Permission.CAN_UPLOAD); 1897 } else if (memberName.equals("can_rename")) { 1898 permissions.add(Permission.CAN_RENAME); 1899 } else if (memberName.equals("can_delete")) { 1900 permissions.add(Permission.CAN_DELETE); 1901 } else if (memberName.equals("can_share")) { 1902 permissions.add(Permission.CAN_SHARE); 1903 } else if (memberName.equals("can_set_share_access")) { 1904 permissions.add(Permission.CAN_SET_SHARE_ACCESS); 1905 } else if (memberName.equals("can_preview")) { 1906 permissions.add(Permission.CAN_PREVIEW); 1907 } else if (memberName.equals("can_comment")) { 1908 permissions.add(Permission.CAN_COMMENT); 1909 } 1910 } 1911 1912 return permissions; 1913 } 1914 1915 private BoxFileVersion parseFileVersion(JsonObject jsonObject) { 1916 return new BoxFileVersion(BoxFile.this.getAPI(), jsonObject, BoxFile.this.getID()); 1917 } 1918 1919 private List<String> parseAllowedInviteeRoles(JsonArray jsonArray) { 1920 List<String> roles = new ArrayList<String>(jsonArray.size()); 1921 for (JsonValue value : jsonArray) { 1922 roles.add(value.asString()); 1923 } 1924 1925 return roles; 1926 } 1927 } 1928 1929 /** 1930 * Enumerates the possible permissions that a user can have on a file. 1931 */ 1932 public enum Permission { 1933 /** 1934 * The user can download the file. 1935 */ 1936 CAN_DOWNLOAD("can_download"), 1937 1938 /** 1939 * The user can upload new versions of the file. 1940 */ 1941 CAN_UPLOAD("can_upload"), 1942 1943 /** 1944 * The user can rename the file. 1945 */ 1946 CAN_RENAME("can_rename"), 1947 1948 /** 1949 * The user can delete the file. 1950 */ 1951 CAN_DELETE("can_delete"), 1952 1953 /** 1954 * The user can share the file. 1955 */ 1956 CAN_SHARE("can_share"), 1957 1958 /** 1959 * The user can set the access level for shared links to the file. 1960 */ 1961 CAN_SET_SHARE_ACCESS("can_set_share_access"), 1962 1963 /** 1964 * The user can preview the file. 1965 */ 1966 CAN_PREVIEW("can_preview"), 1967 1968 /** 1969 * The user can comment on the file. 1970 */ 1971 CAN_COMMENT("can_comment"), 1972 1973 /** 1974 * The user can place annotations on this file. 1975 */ 1976 CAN_ANNOTATE("can_annotate"), 1977 1978 /** 1979 * The current user can invite new users to collaborate on this item, and the user can update the role of a 1980 * user already collaborated on this item. 1981 */ 1982 CAN_INVITE_COLLABORATOR("can_invite_collaborator"), 1983 1984 /** 1985 * The user can view all annotations placed on this file. 1986 */ 1987 CAN_VIEW_ANNOTATIONS_ALL("can_view_annotations_all"), 1988 1989 /** 1990 * The user can view annotations placed by themselves on this file. 1991 */ 1992 CAN_VIEW_ANNOTATIONS_SELF("can_view_annotations_self"); 1993 1994 private final String jsonValue; 1995 1996 private Permission(String jsonValue) { 1997 this.jsonValue = jsonValue; 1998 } 1999 2000 static Permission fromJSONValue(String jsonValue) { 2001 return Permission.valueOf(jsonValue.toUpperCase()); 2002 } 2003 2004 String toJSONValue() { 2005 return this.jsonValue; 2006 } 2007 } 2008 2009}