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