001package com.box.sdk; 002 003import static com.box.sdk.PagingParameters.DEFAULT_LIMIT; 004import static com.box.sdk.PagingParameters.marker; 005import static com.box.sdk.PagingParameters.offset; 006 007import com.box.sdk.internal.utils.Parsers; 008import com.box.sdk.sharedlink.BoxSharedLinkRequest; 009import com.eclipsesource.json.Json; 010import com.eclipsesource.json.JsonArray; 011import com.eclipsesource.json.JsonObject; 012import com.eclipsesource.json.JsonValue; 013import java.io.IOException; 014import java.io.InputStream; 015import java.net.URL; 016import java.util.ArrayList; 017import java.util.Collection; 018import java.util.Date; 019import java.util.EnumSet; 020import java.util.Iterator; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.TimeUnit; 024 025/** 026 * <p>Represents a folder on Box. This class can be used to iterate through a folder's contents, collaborate a folder with 027 * another user or group, and perform other common folder operations (move, copy, delete, etc.). 028 * </p> 029 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 030 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 031 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p> 032 */ 033@BoxResourceType("folder") 034public class BoxFolder extends BoxItem implements Iterable<BoxItem.Info> { 035 /** 036 * An array of all possible folder fields that can be requested when calling {@link #getInfo()}. 037 */ 038 public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "name", "created_at", "modified_at", 039 "description", "size", "path_collection", "created_by", "modified_by", "trashed_at", "purged_at", 040 "content_created_at", "content_modified_at", "owned_by", "shared_link", "folder_upload_email", "parent", 041 "item_status", "item_collection", "sync_state", "has_collaborations", "permissions", "tags", 042 "can_non_owners_invite", "collections", "watermark_info", "metadata", "is_externally_owned", 043 "is_collaboration_restricted_to_enterprise", "allowed_shared_link_access_levels", "allowed_invitee_roles"}; 044 /** 045 * Create Folder URL Template. 046 */ 047 public static final URLTemplate CREATE_FOLDER_URL = new URLTemplate("folders"); 048 /** 049 * Create Web Link URL Template. 050 */ 051 public static final URLTemplate CREATE_WEB_LINK_URL = new URLTemplate("web_links"); 052 /** 053 * Copy Folder URL Template. 054 */ 055 public static final URLTemplate COPY_FOLDER_URL = new URLTemplate("folders/%s/copy"); 056 /** 057 * Delete Folder URL Template. 058 */ 059 public static final URLTemplate DELETE_FOLDER_URL = new URLTemplate("folders/%s?recursive=%b"); 060 /** 061 * Folder Info URL Template. 062 */ 063 public static final URLTemplate FOLDER_INFO_URL_TEMPLATE = new URLTemplate("folders/%s"); 064 /** 065 * Upload File URL Template. 066 */ 067 public static final URLTemplate UPLOAD_FILE_URL = new URLTemplate("files/content"); 068 /** 069 * Add Collaboration URL Template. 070 */ 071 public static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations"); 072 /** 073 * Get Collaborations URL Template. 074 */ 075 public static final URLTemplate GET_COLLABORATIONS_URL = new URLTemplate("folders/%s/collaborations"); 076 /** 077 * Get Items URL Template. 078 */ 079 public static final URLTemplate GET_ITEMS_URL = new URLTemplate("folders/%s/items/"); 080 /** 081 * Search URL Template. 082 */ 083 public static final URLTemplate SEARCH_URL_TEMPLATE = new URLTemplate("search"); 084 /** 085 * Metadata URL Template. 086 */ 087 public static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("folders/%s/metadata/%s/%s"); 088 /** 089 * Upload Session URL Template. 090 */ 091 public static final URLTemplate UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/upload_sessions"); 092 /** 093 * Folder Locks URL Template. 094 */ 095 public static final URLTemplate FOLDER_LOCK_URL_TEMPLATE = new URLTemplate("folder_locks"); 096 097 /** 098 * Constructs a BoxFolder for a folder with a given ID. 099 * 100 * @param api the API connection to be used by the folder. 101 * @param id the ID of the folder. 102 */ 103 public BoxFolder(BoxAPIConnection api, String id) { 104 super(api, id); 105 } 106 107 /** 108 * Gets the current user's root folder. 109 * 110 * @param api the API connection to be used by the folder. 111 * @return the user's root folder. 112 */ 113 public static BoxFolder getRootFolder(BoxAPIConnection api) { 114 return new BoxFolder(api, "0"); 115 } 116 117 /** 118 * {@inheritDoc} 119 */ 120 @Override 121 protected URL getItemURL() { 122 return FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 123 } 124 125 /** 126 * Adds a collaborator to this folder. 127 * 128 * @param collaborator the collaborator to add. 129 * @param role the role of the collaborator. 130 * @return info about the new collaboration. 131 */ 132 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role) { 133 JsonObject accessibleByField = new JsonObject(); 134 accessibleByField.add("id", collaborator.getID()); 135 136 if (collaborator instanceof BoxUser) { 137 accessibleByField.add("type", "user"); 138 } else if (collaborator instanceof BoxGroup) { 139 accessibleByField.add("type", "group"); 140 } else { 141 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 142 } 143 144 return this.collaborate(accessibleByField, role, null, null); 145 } 146 147 /** 148 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 149 * account. 150 * 151 * @param email the email address of the collaborator to add. 152 * @param role the role of the collaborator. 153 * @return info about the new collaboration. 154 */ 155 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role) { 156 JsonObject accessibleByField = new JsonObject(); 157 accessibleByField.add("login", email); 158 accessibleByField.add("type", "user"); 159 160 return this.collaborate(accessibleByField, role, null, null); 161 } 162 163 /** 164 * Adds a collaborator to this folder. 165 * 166 * @param collaborator the collaborator to add. 167 * @param role the role of the collaborator. 168 * @param notify the user/group should receive email notification of the collaboration or not. 169 * @param canViewPath the view path collaboration feature is enabled or not. 170 * View path collaborations allow the invitee to see the entire ancestral path to the associated 171 * folder. The user will not gain privileges in any ancestral folder. 172 * @return info about the new collaboration. 173 */ 174 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role, 175 Boolean notify, Boolean canViewPath) { 176 JsonObject accessibleByField = new JsonObject(); 177 accessibleByField.add("id", collaborator.getID()); 178 179 if (collaborator instanceof BoxUser) { 180 accessibleByField.add("type", "user"); 181 } else if (collaborator instanceof BoxGroup) { 182 accessibleByField.add("type", "group"); 183 } else { 184 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 185 } 186 187 return this.collaborate(accessibleByField, role, notify, canViewPath); 188 } 189 190 /** 191 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 192 * account. 193 * 194 * @param email the email address of the collaborator to add. 195 * @param role the role of the collaborator. 196 * @param notify the user/group should receive email notification of the collaboration or not. 197 * @param canViewPath the view path collaboration feature is enabled or not. 198 * View path collaborations allow the invitee to see the entire ancestral path to the associated 199 * folder. The user will not gain privileges in any ancestral folder. 200 * @return info about the new collaboration. 201 */ 202 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role, 203 Boolean notify, Boolean canViewPath) { 204 JsonObject accessibleByField = new JsonObject(); 205 accessibleByField.add("login", email); 206 accessibleByField.add("type", "user"); 207 208 return this.collaborate(accessibleByField, role, notify, canViewPath); 209 } 210 211 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role, 212 Boolean notify, Boolean canViewPath) { 213 214 JsonObject itemField = new JsonObject(); 215 itemField.add("id", this.getID()); 216 itemField.add("type", "folder"); 217 218 return BoxCollaboration.create(this.getAPI(), accessibleByField, itemField, role, notify, canViewPath); 219 } 220 221 /** 222 * Creates a new shared link for this item. 223 * 224 * <p>This method is a convenience method for manually creating a new shared link and applying it to this item with 225 * {@link BoxItem.Info#setSharedLink}. You may want to create the shared link manually so that it can be updated along with 226 * other changes to the item's info in a single network request, giving a boost to performance.</p> 227 * 228 * @param access the access level of the shared link. 229 * @param unshareDate the date and time at which the link will expire. Can be null to create a non-expiring link. 230 * @param permissions the permissions of the shared link. Can be null to use the default permissions. 231 * @return the created shared link. 232 * @deprecated use {@link BoxFolder#createSharedLink(BoxSharedLinkRequest)} 233 */ 234 @Override 235 @Deprecated 236 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 237 BoxSharedLink.Permissions permissions) { 238 239 return this.createSharedLink(new BoxSharedLink(access, unshareDate, permissions)); 240 } 241 242 /** 243 * Creates new SharedLink for a BoxFolder with a password. 244 * 245 * @param access The access level of the shared link. 246 * @param unshareDate A specified date to unshare the Box folder. 247 * @param permissions The permissions to set on the shared link for the Box folder. 248 * @param password Password set on the shared link to give access to the Box folder. 249 * @return information about the newly created shared link. 250 * @deprecated Use {@link BoxFolder#createSharedLink(BoxSharedLinkRequest)} 251 */ 252 @Deprecated 253 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 254 BoxSharedLink.Permissions permissions, String password) { 255 256 return this.createSharedLink(new BoxSharedLink(access, unshareDate, permissions, password)); 257 } 258 259 /** 260 * Creates a shared link. 261 * 262 * @param sharedLinkRequest Shared link to create 263 * @return Created shared link. 264 */ 265 public BoxSharedLink createSharedLink(BoxSharedLinkRequest sharedLinkRequest) { 266 return createSharedLink(sharedLinkRequest.asSharedLink()); 267 } 268 269 private BoxSharedLink createSharedLink(BoxSharedLink sharedLink) { 270 BoxFolder.Info info = new BoxFolder.Info(); 271 info.setSharedLink(removeCanEditPermissionIfSet(sharedLink)); 272 273 this.updateInfo(info); 274 return info.getSharedLink(); 275 } 276 277 private BoxSharedLink removeCanEditPermissionIfSet(BoxSharedLink sharedLink) { 278 if (sharedLink.getPermissions() != null && sharedLink.getPermissions().getCanEdit()) { 279 BoxSharedLink.Permissions permissions = sharedLink.getPermissions(); 280 sharedLink.setPermissions( 281 new BoxSharedLink.Permissions(permissions.getCanPreview(), permissions.getCanDownload(), false) 282 ); 283 } 284 return sharedLink; 285 } 286 287 /** 288 * Gets information about all of the collaborations for this folder. 289 * 290 * @return a collection of information about the collaborations for this folder. 291 */ 292 public Collection<BoxCollaboration.Info> getCollaborations() { 293 BoxAPIConnection api = this.getAPI(); 294 URL url = GET_COLLABORATIONS_URL.build(api.getBaseURL(), this.getID()); 295 296 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 297 BoxJSONResponse response = (BoxJSONResponse) request.send(); 298 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 299 300 int entriesCount = responseJSON.get("total_count").asInt(); 301 Collection<BoxCollaboration.Info> collaborations = new ArrayList<>(entriesCount); 302 JsonArray entries = responseJSON.get("entries").asArray(); 303 for (JsonValue entry : entries) { 304 JsonObject entryObject = entry.asObject(); 305 BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString()); 306 BoxCollaboration.Info info = collaboration.new Info(entryObject); 307 collaborations.add(info); 308 } 309 310 return collaborations; 311 } 312 313 @Override 314 public BoxFolder.Info getInfo() { 315 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 316 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 317 BoxJSONResponse response = (BoxJSONResponse) request.send(); 318 return new Info(response.getJSON()); 319 } 320 321 @Override 322 public BoxFolder.Info getInfo(String... fields) { 323 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 324 URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 325 326 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 327 BoxJSONResponse response = (BoxJSONResponse) request.send(); 328 return new Info(response.getJSON()); 329 } 330 331 /** 332 * Updates the information about this folder with any info fields that have been modified locally. 333 * 334 * @param info the updated info. 335 */ 336 public void updateInfo(BoxFolder.Info info) { 337 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 338 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 339 request.setBody(info.getPendingChanges()); 340 BoxJSONResponse response = (BoxJSONResponse) request.send(); 341 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 342 info.update(jsonObject); 343 } 344 345 @Override 346 public BoxFolder.Info copy(BoxFolder destination) { 347 return this.copy(destination, null); 348 } 349 350 @Override 351 public BoxFolder.Info copy(BoxFolder destination, String newName) { 352 URL url = COPY_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID()); 353 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 354 355 JsonObject parent = new JsonObject(); 356 parent.add("id", destination.getID()); 357 358 JsonObject copyInfo = new JsonObject(); 359 copyInfo.add("parent", parent); 360 if (newName != null) { 361 copyInfo.add("name", newName); 362 } 363 364 request.setBody(copyInfo.toString()); 365 BoxJSONResponse response = (BoxJSONResponse) request.send(); 366 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 367 BoxFolder copiedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 368 return copiedFolder.new Info(responseJSON); 369 } 370 371 /** 372 * Creates a new child folder inside this folder. 373 * 374 * @param name the new folder's name. 375 * @return the created folder's info. 376 */ 377 public BoxFolder.Info createFolder(String name) { 378 JsonObject parent = new JsonObject(); 379 parent.add("id", this.getID()); 380 381 JsonObject newFolder = new JsonObject(); 382 newFolder.add("name", name); 383 newFolder.add("parent", parent); 384 385 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), CREATE_FOLDER_URL.build(this.getAPI().getBaseURL()), 386 "POST"); 387 request.setBody(newFolder.toString()); 388 BoxJSONResponse response = (BoxJSONResponse) request.send(); 389 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 390 391 BoxFolder createdFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 392 return createdFolder.new Info(responseJSON); 393 } 394 395 /** 396 * Deletes this folder, optionally recursively deleting all of its contents. 397 * 398 * @param recursive true to recursively delete this folder's contents; otherwise false. 399 */ 400 public void delete(boolean recursive) { 401 URL url = DELETE_FOLDER_URL.buildAlpha(this.getAPI().getBaseURL(), this.getID(), recursive); 402 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 403 BoxAPIResponse response = request.send(); 404 response.disconnect(); 405 } 406 407 @Override 408 public BoxItem.Info move(BoxFolder destination) { 409 return this.move(destination, null); 410 } 411 412 @Override 413 public BoxItem.Info move(BoxFolder destination, String newName) { 414 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 415 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 416 417 JsonObject parent = new JsonObject(); 418 parent.add("id", destination.getID()); 419 420 JsonObject updateInfo = new JsonObject(); 421 updateInfo.add("parent", parent); 422 if (newName != null) { 423 updateInfo.add("name", newName); 424 } 425 426 request.setBody(updateInfo.toString()); 427 BoxJSONResponse response = (BoxJSONResponse) request.send(); 428 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 429 BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 430 return movedFolder.new Info(responseJSON); 431 } 432 433 /** 434 * Renames this folder. 435 * 436 * @param newName the new name of the folder. 437 */ 438 public void rename(String newName) { 439 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 440 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 441 442 JsonObject updateInfo = new JsonObject(); 443 updateInfo.add("name", newName); 444 445 request.setBody(updateInfo.toString()); 446 BoxJSONResponse response = (BoxJSONResponse) request.send(); 447 response.getJSON(); 448 } 449 450 /** 451 * Checks if the file can be successfully uploaded by using the preflight check. 452 * 453 * @param name the name to give the uploaded file. 454 * @param fileSize the size of the file used for account capacity calculations. 455 */ 456 public void canUpload(String name, long fileSize) { 457 URL url = UPLOAD_FILE_URL.build(this.getAPI().getBaseURL()); 458 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 459 460 JsonObject parent = new JsonObject(); 461 parent.add("id", this.getID()); 462 463 JsonObject preflightInfo = new JsonObject(); 464 preflightInfo.add("parent", parent); 465 preflightInfo.add("name", name); 466 467 preflightInfo.add("size", fileSize); 468 469 request.setBody(preflightInfo.toString()); 470 BoxJSONResponse response = (BoxJSONResponse) request.send(); 471 response.getJSON(); 472 } 473 474 /** 475 * Uploads a new file to this folder. 476 * 477 * @param fileContent a stream containing the contents of the file to upload. 478 * @param name the name to give the uploaded file. 479 * @return the uploaded file's info. 480 */ 481 public BoxFile.Info uploadFile(InputStream fileContent, String name) { 482 FileUploadParams uploadInfo = new FileUploadParams() 483 .setContent(fileContent) 484 .setName(name); 485 return this.uploadFile(uploadInfo); 486 } 487 488 /** 489 * Uploads a new file to this folder. 490 * 491 * @param callback the callback which allows file content to be written on output stream. 492 * @param name the name to give the uploaded file. 493 * @return the uploaded file's info. 494 */ 495 public BoxFile.Info uploadFile(UploadFileCallback callback, String name) { 496 FileUploadParams uploadInfo = new FileUploadParams() 497 .setUploadFileCallback(callback) 498 .setName(name); 499 return this.uploadFile(uploadInfo); 500 } 501 502 /** 503 * Uploads a new file to this folder while reporting the progress to a ProgressListener. 504 * 505 * @param fileContent a stream containing the contents of the file to upload. 506 * @param name the name to give the uploaded file. 507 * @param fileSize the size of the file used for determining the progress of the upload. 508 * @param listener a listener for monitoring the upload's progress. 509 * @return the uploaded file's info. 510 */ 511 public BoxFile.Info uploadFile(InputStream fileContent, String name, long fileSize, ProgressListener listener) { 512 FileUploadParams uploadInfo = new FileUploadParams() 513 .setContent(fileContent) 514 .setName(name) 515 .setSize(fileSize) 516 .setProgressListener(listener); 517 return this.uploadFile(uploadInfo); 518 } 519 520 /** 521 * Uploads a new file to this folder with a specified file description. 522 * 523 * @param fileContent a stream containing the contents of the file to upload. 524 * @param name the name to give the uploaded file. 525 * @param description the description to give the uploaded file. 526 * @return the uploaded file's info. 527 */ 528 public BoxFile.Info uploadFile(InputStream fileContent, String name, String description) { 529 FileUploadParams uploadInfo = new FileUploadParams() 530 .setContent(fileContent) 531 .setName(name) 532 .setDescription(description); 533 return this.uploadFile(uploadInfo); 534 } 535 536 /** 537 * Uploads a new file to this folder with custom upload parameters. 538 * 539 * @param uploadParams the custom upload parameters. 540 * @return the uploaded file's info. 541 */ 542 public BoxFile.Info uploadFile(FileUploadParams uploadParams) { 543 URL uploadURL = UPLOAD_FILE_URL.build(this.getAPI().getBaseUploadURL()); 544 BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL); 545 546 JsonObject fieldJSON = new JsonObject(); 547 JsonObject parentIdJSON = new JsonObject(); 548 parentIdJSON.add("id", getID()); 549 fieldJSON.add("name", uploadParams.getName()); 550 fieldJSON.add("parent", parentIdJSON); 551 552 if (uploadParams.getCreated() != null) { 553 fieldJSON.add("content_created_at", BoxDateFormat.format(uploadParams.getCreated())); 554 } 555 556 if (uploadParams.getModified() != null) { 557 fieldJSON.add("content_modified_at", BoxDateFormat.format(uploadParams.getModified())); 558 } 559 560 if (uploadParams.getSHA1() != null && !uploadParams.getSHA1().isEmpty()) { 561 request.setContentSHA1(uploadParams.getSHA1()); 562 } 563 564 if (uploadParams.getDescription() != null) { 565 fieldJSON.add("description", uploadParams.getDescription()); 566 } 567 568 request.putField("attributes", fieldJSON.toString()); 569 570 if (uploadParams.getSize() > 0) { 571 request.setFile(uploadParams.getContent(), uploadParams.getName(), uploadParams.getSize()); 572 } else if (uploadParams.getContent() != null) { 573 request.setFile(uploadParams.getContent(), uploadParams.getName()); 574 } else { 575 request.setUploadFileCallback(uploadParams.getUploadFileCallback(), uploadParams.getName()); 576 } 577 578 BoxJSONResponse response; 579 if (uploadParams.getProgressListener() == null) { 580 response = (BoxJSONResponse) request.send(); 581 } else { 582 response = (BoxJSONResponse) request.send(uploadParams.getProgressListener()); 583 } 584 JsonObject collection = Json.parse(response.getJSON()).asObject(); 585 JsonArray entries = collection.get("entries").asArray(); 586 JsonObject fileInfoJSON = entries.get(0).asObject(); 587 String uploadedFileID = fileInfoJSON.get("id").asString(); 588 589 BoxFile uploadedFile = new BoxFile(getAPI(), uploadedFileID); 590 return uploadedFile.new Info(fileInfoJSON); 591 } 592 593 /** 594 * Uploads a new weblink to this folder. 595 * 596 * @param linkURL the URL the weblink points to. 597 * @return the uploaded weblink's info. 598 */ 599 public BoxWebLink.Info createWebLink(URL linkURL) { 600 return this.createWebLink(null, linkURL, 601 null); 602 } 603 604 /** 605 * Uploads a new weblink to this folder. 606 * 607 * @param name the filename for the weblink. 608 * @param linkURL the URL the weblink points to. 609 * @return the uploaded weblink's info. 610 */ 611 public BoxWebLink.Info createWebLink(String name, URL linkURL) { 612 return this.createWebLink(name, linkURL, 613 null); 614 } 615 616 /** 617 * Uploads a new weblink to this folder. 618 * 619 * @param linkURL the URL the weblink points to. 620 * @param description the weblink's description. 621 * @return the uploaded weblink's info. 622 */ 623 public BoxWebLink.Info createWebLink(URL linkURL, String description) { 624 return this.createWebLink(null, linkURL, description); 625 } 626 627 /** 628 * Uploads a new weblink to this folder. 629 * 630 * @param name the filename for the weblink. 631 * @param linkURL the URL the weblink points to. 632 * @param description the weblink's description. 633 * @return the uploaded weblink's info. 634 */ 635 public BoxWebLink.Info createWebLink(String name, URL linkURL, String description) { 636 JsonObject parent = new JsonObject(); 637 parent.add("id", this.getID()); 638 639 JsonObject newWebLink = new JsonObject(); 640 newWebLink.add("name", name); 641 newWebLink.add("parent", parent); 642 newWebLink.add("url", linkURL.toString()); 643 644 if (description != null) { 645 newWebLink.add("description", description); 646 } 647 648 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), 649 CREATE_WEB_LINK_URL.build(this.getAPI().getBaseURL()), "POST"); 650 request.setBody(newWebLink.toString()); 651 BoxJSONResponse response = (BoxJSONResponse) request.send(); 652 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 653 654 BoxWebLink createdWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString()); 655 return createdWebLink.new Info(responseJSON); 656 } 657 658 /** 659 * Returns an iterable containing the items in this folder. Iterating over the iterable returned by this method is 660 * equivalent to iterating over this BoxFolder directly. 661 * 662 * @return an iterable containing the items in this folder. 663 */ 664 public Iterable<BoxItem.Info> getChildren() { 665 return this; 666 } 667 668 /** 669 * Returns an iterable containing the items in this folder and specifies which child fields to retrieve from the 670 * API. 671 * 672 * @param fields the fields to retrieve. 673 * @return an iterable containing the items in this folder. 674 */ 675 public Iterable<BoxItem.Info> getChildren(final String... fields) { 676 return () -> { 677 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 678 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), queryString, getID()); 679 return new BoxItemIterator(getAPI(), url, marker(DEFAULT_LIMIT)); 680 }; 681 } 682 683 /** 684 * Returns an iterable containing the items in this folder sorted by name and direction. 685 * 686 * @param sort the field to sort by, can be set as `name`, `id`, and `date`. 687 * @param direction the direction to display the item results. 688 * @param fields the fields to retrieve. 689 * @return an iterable containing the items in this folder. 690 */ 691 public Iterable<BoxItem.Info> getChildren(String sort, SortDirection direction, final String... fields) { 692 QueryStringBuilder builder = new QueryStringBuilder() 693 .appendParam("sort", sort) 694 .appendParam("direction", direction.toString()); 695 696 if (fields.length > 0) { 697 builder.appendParam("fields", fields); 698 } 699 final String query = builder.toString(); 700 return () -> { 701 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID()); 702 return new BoxItemIterator(getAPI(), url, offset(0, DEFAULT_LIMIT)); 703 }; 704 } 705 706 /** 707 * Returns an iterable containing the items in this folder sorted by name and direction. 708 * 709 * @param sort the field to sort by, can be set as `name`, `id`, and `date`. 710 * @param direction the direction to display the item results. 711 * @param offset the index of the first child item to retrieve. 712 * @param limit the maximum number of children to retrieve after the offset. 713 * @param fields the fields to retrieve. 714 * @return an iterable containing the items in this folder. 715 */ 716 public Iterable<BoxItem.Info> getChildren(String sort, SortDirection direction, final long offset, final long limit, 717 final String... fields) { 718 QueryStringBuilder builder = new QueryStringBuilder() 719 .appendParam("sort", sort) 720 .appendParam("direction", direction.toString()); 721 722 if (fields.length > 0) { 723 builder.appendParam("fields", fields); 724 } 725 final String query = builder.toString(); 726 return () -> { 727 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID()); 728 return new BoxItemIterator(getAPI(), url, limit, offset); 729 }; 730 } 731 732 /** 733 * Retrieves a specific range of child items in this folder. 734 * 735 * @param offset the index of the first child item to retrieve. 736 * @param limit the maximum number of children to retrieve after the offset. 737 * @param fields the fields to retrieve. 738 * @return a partial collection containing the specified range of child items. 739 */ 740 public PartialCollection<BoxItem.Info> getChildrenRange(long offset, long limit, String... fields) { 741 QueryStringBuilder builder = new QueryStringBuilder() 742 .appendParam("limit", limit) 743 .appendParam("offset", offset); 744 745 if (fields.length > 0) { 746 builder.appendParam("fields", fields); 747 } 748 749 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), builder.toString(), getID()); 750 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 751 BoxJSONResponse response = (BoxJSONResponse) request.send(); 752 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 753 754 String totalCountString = responseJSON.get("total_count").toString(); 755 long fullSize = Double.valueOf(totalCountString).longValue(); 756 PartialCollection<BoxItem.Info> children = new PartialCollection<>(offset, limit, fullSize); 757 JsonArray jsonArray = responseJSON.get("entries").asArray(); 758 for (JsonValue value : jsonArray) { 759 JsonObject jsonObject = value.asObject(); 760 BoxItem.Info parsedItemInfo = (BoxItem.Info) BoxResource.parseInfo(this.getAPI(), jsonObject); 761 if (parsedItemInfo != null) { 762 children.add(parsedItemInfo); 763 } 764 } 765 return children; 766 } 767 768 /** 769 * Returns an iterable containing the items in this folder sorted by name and direction. 770 * 771 * @param sortParameters describes sorting parameters. 772 * Sort parameters are supported only with offset based pagination. 773 * Use {@link SortParameters#none()} to ignore sorting. 774 * @param pagingParameters describes paging parameters. 775 * @param fields the fields to retrieve. 776 * @return an iterable containing the items in this folder. 777 */ 778 public Iterable<BoxItem.Info> getChildren( 779 final SortParameters sortParameters, final PagingParameters pagingParameters, String... fields 780 ) { 781 QueryStringBuilder builder = sortParameters.asQueryStringBuilder(); 782 validateSortIsSelectedWithOffsetPaginationOnly(pagingParameters, builder); 783 784 if (fields.length > 0) { 785 builder.appendParam("fields", fields); 786 } 787 final String query = builder.toString(); 788 return () -> { 789 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID()); 790 return new BoxItemIterator(getAPI(), url, pagingParameters); 791 }; 792 } 793 794 /** 795 * Returns an iterator over the items in this folder. 796 * 797 * @return an iterator over the items in this folder. 798 */ 799 @Override 800 public Iterator<BoxItem.Info> iterator() { 801 URL url = GET_ITEMS_URL.build(this.getAPI().getBaseURL(), BoxFolder.this.getID()); 802 return new BoxItemIterator(BoxFolder.this.getAPI(), url, marker(DEFAULT_LIMIT)); 803 } 804 805 /** 806 * Adds new {@link BoxWebHook} to this {@link BoxFolder}. 807 * 808 * @param address {@link BoxWebHook.Info#getAddress()} 809 * @param triggers {@link BoxWebHook.Info#getTriggers()} 810 * @return created {@link BoxWebHook.Info} 811 */ 812 public BoxWebHook.Info addWebHook(URL address, BoxWebHook.Trigger... triggers) { 813 return BoxWebHook.create(this, address, triggers); 814 } 815 816 /** 817 * Used to retrieve the watermark for the folder. 818 * If the folder does not have a watermark applied to it, a 404 Not Found will be returned by API. 819 * 820 * @param fields the fields to retrieve. 821 * @return the watermark associated with the folder. 822 */ 823 public BoxWatermark getWatermark(String... fields) { 824 return this.getWatermark(FOLDER_INFO_URL_TEMPLATE, fields); 825 } 826 827 /** 828 * Used to apply or update the watermark for the folder. 829 * 830 * @return the watermark associated with the folder. 831 */ 832 public BoxWatermark applyWatermark() { 833 return this.applyWatermark(FOLDER_INFO_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT); 834 } 835 836 /** 837 * Removes a watermark from the folder. 838 * If the folder did not have a watermark applied to it, a 404 Not Found will be returned by API. 839 */ 840 public void removeWatermark() { 841 this.removeWatermark(FOLDER_INFO_URL_TEMPLATE); 842 } 843 844 /** 845 * Used to retrieve all metadata associated with the folder. 846 * 847 * @param fields the optional fields to retrieve. 848 * @return An iterable of metadata instances associated with the folder 849 */ 850 public Iterable<Metadata> getAllMetadata(String... fields) { 851 return Metadata.getAllMetadata(this, fields); 852 } 853 854 /** 855 * This method is deprecated, please use the {@link BoxSearch} class instead. 856 * Searches this folder and all descendant folders using a given queryPlease use BoxSearch Instead. 857 * 858 * @param query the search query. 859 * @return an Iterable containing the search results. 860 */ 861 @Deprecated 862 public Iterable<BoxItem.Info> search(final String query) { 863 return () -> { 864 QueryStringBuilder builder = new QueryStringBuilder(); 865 builder.appendParam("query", query); 866 builder.appendParam("ancestor_folder_ids", getID()); 867 868 URL url = SEARCH_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), builder.toString()); 869 return new BoxItemIterator(getAPI(), url); 870 }; 871 } 872 873 @Override 874 public BoxFolder.Info setCollections(BoxCollection... collections) { 875 JsonArray jsonArray = new JsonArray(); 876 for (BoxCollection collection : collections) { 877 JsonObject collectionJSON = new JsonObject(); 878 collectionJSON.add("id", collection.getID()); 879 jsonArray.add(collectionJSON); 880 } 881 JsonObject infoJSON = new JsonObject(); 882 infoJSON.add("collections", jsonArray); 883 884 String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString(); 885 URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 886 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 887 request.setBody(infoJSON.toString()); 888 BoxJSONResponse response = (BoxJSONResponse) request.send(); 889 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 890 return new Info(jsonObject); 891 } 892 893 /** 894 * Creates global property metadata on this folder. 895 * 896 * @param metadata the new metadata values. 897 * @return the metadata returned from the server. 898 */ 899 public Metadata createMetadata(Metadata metadata) { 900 return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata); 901 } 902 903 /** 904 * Creates metadata on this folder using a specified template. 905 * 906 * @param templateName the name of the metadata template. 907 * @param metadata the new metadata values. 908 * @return the metadata returned from the server. 909 */ 910 public Metadata createMetadata(String templateName, Metadata metadata) { 911 String scope = Metadata.scopeBasedOnType(templateName); 912 return this.createMetadata(templateName, scope, metadata); 913 } 914 915 /** 916 * Creates metadata on this folder using a specified scope and template. 917 * 918 * @param templateName the name of the metadata template. 919 * @param scope the scope of the template (usually "global" or "enterprise"). 920 * @param metadata the new metadata values. 921 * @return the metadata returned from the server. 922 */ 923 public Metadata createMetadata(String templateName, String scope, Metadata metadata) { 924 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 925 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST"); 926 request.addHeader("Content-Type", "application/json"); 927 request.setBody(metadata.toString()); 928 BoxJSONResponse response = (BoxJSONResponse) request.send(); 929 return new Metadata(Json.parse(response.getJSON()).asObject()); 930 } 931 932 /** 933 * Sets the provided metadata on the folder. If metadata has already been created on this folder, 934 * it overwrites metadata keys specified in the `metadata` param. 935 * 936 * @param templateName the name of the metadata template. 937 * @param scope the scope of the template (usually "global" or "enterprise"). 938 * @param metadata the new metadata values. 939 * @return the metadata returned from the server. 940 */ 941 public Metadata setMetadata(String templateName, String scope, Metadata metadata) { 942 try { 943 return this.createMetadata(templateName, scope, metadata); 944 } catch (BoxAPIException e) { 945 if (e.getResponseCode() == 409) { 946 if (metadata.getOperations().isEmpty()) { 947 return getMetadata(); 948 } else { 949 return updateExistingTemplate(templateName, scope, metadata); 950 } 951 } else { 952 throw e; 953 } 954 } 955 } 956 957 /** 958 * Throws IllegalArgumentException exception when sorting and marker pagination is selected. 959 * 960 * @param pagingParameters paging definition to check 961 * @param sortQuery builder containing sort query 962 */ 963 private void validateSortIsSelectedWithOffsetPaginationOnly( 964 PagingParameters pagingParameters, 965 QueryStringBuilder sortQuery 966 ) { 967 if (pagingParameters != null && pagingParameters.isMarkerBasedPaging() && sortQuery.toString().length() > 0) { 968 throw new IllegalArgumentException("Sorting is not supported when using marker based pagination."); 969 } 970 } 971 972 private Metadata updateExistingTemplate(String templateName, String scope, Metadata metadata) { 973 Metadata metadataToUpdate = new Metadata(scope, templateName); 974 for (JsonValue value : metadata.getOperations()) { 975 if (value.asObject().get("value").isNumber()) { 976 metadataToUpdate.add(value.asObject().get("path").asString(), 977 value.asObject().get("value").asDouble()); 978 } else if (value.asObject().get("value").isString()) { 979 metadataToUpdate.add(value.asObject().get("path").asString(), 980 value.asObject().get("value").asString()); 981 } else if (value.asObject().get("value").isArray()) { 982 ArrayList<String> list = new ArrayList<>(); 983 for (JsonValue jsonValue : value.asObject().get("value").asArray()) { 984 list.add(jsonValue.asString()); 985 } 986 metadataToUpdate.add(value.asObject().get("path").asString(), list); 987 } 988 } 989 return this.updateMetadata(metadataToUpdate); 990 } 991 992 /** 993 * Gets the global properties metadata on this folder. 994 * 995 * @return the metadata returned from the server. 996 */ 997 public Metadata getMetadata() { 998 return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE); 999 } 1000 1001 /** 1002 * Gets the metadata on this folder associated with a specified template. 1003 * 1004 * @param templateName the metadata template type name. 1005 * @return the metadata returned from the server. 1006 */ 1007 public Metadata getMetadata(String templateName) { 1008 String scope = Metadata.scopeBasedOnType(templateName); 1009 return this.getMetadata(templateName, scope); 1010 } 1011 1012 /** 1013 * Gets the metadata on this folder associated with a specified scope and template. 1014 * 1015 * @param templateName the metadata template type name. 1016 * @param scope the scope of the template (usually "global" or "enterprise"). 1017 * @return the metadata returned from the server. 1018 */ 1019 public Metadata getMetadata(String templateName, String scope) { 1020 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 1021 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 1022 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1023 return new Metadata(Json.parse(response.getJSON()).asObject()); 1024 } 1025 1026 /** 1027 * Updates the folder metadata. 1028 * 1029 * @param metadata the new metadata values. 1030 * @return the metadata returned from the server. 1031 */ 1032 public Metadata updateMetadata(Metadata metadata) { 1033 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), metadata.getScope(), 1034 metadata.getTemplateName()); 1035 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 1036 request.addHeader("Content-Type", "application/json-patch+json"); 1037 request.setBody(metadata.getPatch()); 1038 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1039 return new Metadata(Json.parse(response.getJSON()).asObject()); 1040 } 1041 1042 /** 1043 * Deletes the global properties metadata on this folder. 1044 */ 1045 public void deleteMetadata() { 1046 this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE); 1047 } 1048 1049 /** 1050 * Deletes the metadata on this folder associated with a specified template. 1051 * 1052 * @param templateName the metadata template type name. 1053 */ 1054 public void deleteMetadata(String templateName) { 1055 String scope = Metadata.scopeBasedOnType(templateName); 1056 this.deleteMetadata(templateName, scope); 1057 } 1058 1059 /** 1060 * Deletes the metadata on this folder associated with a specified scope and template. 1061 * 1062 * @param templateName the metadata template type name. 1063 * @param scope the scope of the template (usually "global" or "enterprise"). 1064 */ 1065 public void deleteMetadata(String templateName, String scope) { 1066 URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 1067 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 1068 BoxAPIResponse response = request.send(); 1069 response.disconnect(); 1070 } 1071 1072 /** 1073 * Adds a metadata classification to the specified file. 1074 * 1075 * @param classificationType the metadata classification type. 1076 * @return the metadata classification type added to the file. 1077 */ 1078 public String addClassification(String classificationType) { 1079 Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType); 1080 Metadata classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, 1081 "enterprise", metadata); 1082 1083 return classification.getString(Metadata.CLASSIFICATION_KEY); 1084 } 1085 1086 /** 1087 * Updates a metadata classification on the specified file. 1088 * 1089 * @param classificationType the metadata classification type. 1090 * @return the new metadata classification type updated on the file. 1091 */ 1092 public String updateClassification(String classificationType) { 1093 Metadata metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY); 1094 metadata.replace(Metadata.CLASSIFICATION_KEY, classificationType); 1095 Metadata classification = this.updateMetadata(metadata); 1096 1097 return classification.getString(Metadata.CLASSIFICATION_KEY); 1098 } 1099 1100 /** 1101 * Attempts to add classification to a file. If classification already exists then do update. 1102 * 1103 * @param classificationType the metadata classification type. 1104 * @return the metadata classification type on the file. 1105 */ 1106 public String setClassification(String classificationType) { 1107 Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType); 1108 Metadata classification; 1109 1110 try { 1111 classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise", metadata); 1112 } catch (BoxAPIException e) { 1113 if (e.getResponseCode() == 409) { 1114 metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY); 1115 metadata.replace(Metadata.CLASSIFICATION_KEY, classificationType); 1116 classification = this.updateMetadata(metadata); 1117 } else { 1118 throw e; 1119 } 1120 } 1121 1122 return classification.getString("/Box__Security__Classification__Key"); 1123 } 1124 1125 /** 1126 * Gets the classification type for the specified file. 1127 * 1128 * @return the metadata classification type on the file. 1129 */ 1130 public String getClassification() { 1131 Metadata metadata = this.getMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY); 1132 return metadata.getString(Metadata.CLASSIFICATION_KEY); 1133 } 1134 1135 /** 1136 * Deletes the classification on the file. 1137 */ 1138 public void deleteClassification() { 1139 this.deleteMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise"); 1140 } 1141 1142 /** 1143 * Creates an upload session to create a new file in chunks. 1144 * This will first verify that the file can be created and then open a session for uploading pieces of the file. 1145 * 1146 * @param fileName the name of the file to be created 1147 * @param fileSize the size of the file that will be uploaded 1148 * @return the created upload session instance 1149 */ 1150 public BoxFileUploadSession.Info createUploadSession(String fileName, long fileSize) { 1151 1152 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 1153 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 1154 1155 JsonObject body = new JsonObject(); 1156 body.add("folder_id", this.getID()); 1157 body.add("file_name", fileName); 1158 body.add("file_size", fileSize); 1159 request.setBody(body.toString()); 1160 1161 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1162 JsonObject jsonObject = Json.parse(response.getJSON()).asObject(); 1163 1164 String sessionId = jsonObject.get("id").asString(); 1165 BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId); 1166 1167 return session.new Info(jsonObject); 1168 } 1169 1170 /** 1171 * Creates a new file. 1172 * 1173 * @param inputStream the stream instance that contains the data. 1174 * @param fileName the name of the file to be created. 1175 * @param fileSize the size of the file that will be uploaded. 1176 * @return the created file instance. 1177 * @throws InterruptedException when a thread execution is interrupted. 1178 * @throws IOException when reading a stream throws exception. 1179 */ 1180 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize) 1181 throws InterruptedException, IOException { 1182 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 1183 this.canUpload(fileName, fileSize); 1184 return new LargeFileUpload(). 1185 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize); 1186 } 1187 1188 /** 1189 * Creates a new file. Also sets file attributes. 1190 * 1191 * @param inputStream the stream instance that contains the data. 1192 * @param fileName the name of the file to be created. 1193 * @param fileSize the size of the file that will be uploaded. 1194 * @param fileAttributes file attributes to set 1195 * @return the created file instance. 1196 * @throws InterruptedException when a thread execution is interrupted. 1197 * @throws IOException when reading a stream throws exception. 1198 */ 1199 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize, 1200 Map<String, String> fileAttributes) 1201 throws InterruptedException, IOException { 1202 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 1203 this.canUpload(fileName, fileSize); 1204 return new LargeFileUpload(). 1205 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize, fileAttributes); 1206 } 1207 1208 /** 1209 * Creates a new file using specified number of parallel http connections. 1210 * 1211 * @param inputStream the stream instance that contains the data. 1212 * @param fileName the name of the file to be created. 1213 * @param fileSize the size of the file that will be uploaded. 1214 * @param nParallelConnections number of parallel http connections to use 1215 * @param timeOut time to wait before killing the job 1216 * @param unit time unit for the time wait value 1217 * @return the created file instance. 1218 * @throws InterruptedException when a thread execution is interrupted. 1219 * @throws IOException when reading a stream throws exception. 1220 */ 1221 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize, 1222 int nParallelConnections, long timeOut, TimeUnit unit) 1223 throws InterruptedException, IOException { 1224 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 1225 this.canUpload(fileName, fileSize); 1226 return new LargeFileUpload(nParallelConnections, timeOut, unit). 1227 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize); 1228 } 1229 1230 /** 1231 * Creates a new file using specified number of parallel http connections. Also sets file attributes. 1232 * 1233 * @param inputStream the stream instance that contains the data. 1234 * @param fileName the name of the file to be created. 1235 * @param fileSize the size of the file that will be uploaded. 1236 * @param nParallelConnections number of parallel http connections to use 1237 * @param timeOut time to wait before killing the job 1238 * @param unit time unit for the time wait value 1239 * @param fileAttributes file attributes to set 1240 * @return the created file instance. 1241 * @throws InterruptedException when a thread execution is interrupted. 1242 * @throws IOException when reading a stream throws exception. 1243 */ 1244 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize, 1245 int nParallelConnections, long timeOut, TimeUnit unit, 1246 Map<String, String> fileAttributes) 1247 throws InterruptedException, IOException { 1248 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 1249 this.canUpload(fileName, fileSize); 1250 return new LargeFileUpload(nParallelConnections, timeOut, unit). 1251 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize, fileAttributes); 1252 } 1253 1254 /** 1255 * Creates a new Metadata Cascade Policy on a folder. 1256 * 1257 * @param scope the scope of the metadata cascade policy. 1258 * @param templateKey the key of the template. 1259 * @return information about the Metadata Cascade Policy. 1260 */ 1261 public BoxMetadataCascadePolicy.Info addMetadataCascadePolicy(String scope, String templateKey) { 1262 1263 return BoxMetadataCascadePolicy.create(this.getAPI(), this.getID(), scope, templateKey); 1264 } 1265 1266 /** 1267 * Retrieves all Metadata Cascade Policies on a folder. 1268 * 1269 * @param fields optional fields to retrieve for cascade policies. 1270 * @return the Iterable of Box Metadata Cascade Policies in your enterprise. 1271 */ 1272 public Iterable<BoxMetadataCascadePolicy.Info> getMetadataCascadePolicies(String... fields) { 1273 return BoxMetadataCascadePolicy.getAll(this.getAPI(), this.getID(), fields); 1274 } 1275 1276 /** 1277 * Retrieves all Metadata Cascade Policies on a folder. 1278 * 1279 * @param enterpriseID the ID of the enterprise to retrieve cascade policies for. 1280 * @param limit the number of entries of cascade policies to retrieve. 1281 * @param fields optional fields to retrieve for cascade policies. 1282 * @return the Iterable of Box Metadata Cascade Policies in your enterprise. 1283 */ 1284 public Iterable<BoxMetadataCascadePolicy.Info> getMetadataCascadePolicies(String enterpriseID, 1285 int limit, String... fields) { 1286 1287 return BoxMetadataCascadePolicy.getAll(this.getAPI(), this.getID(), enterpriseID, limit, fields); 1288 } 1289 1290 /** 1291 * Lock this folder. 1292 * 1293 * @return a created folder lock object. 1294 */ 1295 public BoxFolderLock.Info lock() { 1296 JsonObject folderObject = new JsonObject(); 1297 folderObject.add("type", "folder"); 1298 folderObject.add("id", this.getID()); 1299 1300 JsonObject lockedOperations = new JsonObject(); 1301 lockedOperations.add("move", true); 1302 lockedOperations.add("delete", true); 1303 1304 1305 JsonObject body = new JsonObject(); 1306 body.add("folder", folderObject); 1307 body.add("locked_operations", lockedOperations); 1308 1309 BoxJSONRequest request = 1310 new BoxJSONRequest(this.getAPI(), FOLDER_LOCK_URL_TEMPLATE.build(this.getAPI().getBaseURL()), 1311 "POST"); 1312 request.setBody(body.toString()); 1313 BoxJSONResponse response = (BoxJSONResponse) request.send(); 1314 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 1315 1316 BoxFolderLock createdFolderLock = new BoxFolderLock(this.getAPI(), responseJSON.get("id").asString()); 1317 return createdFolderLock.new Info(responseJSON); 1318 } 1319 1320 /** 1321 * Get the lock on this folder. 1322 * 1323 * @return a folder lock object. 1324 */ 1325 public Iterable<BoxFolderLock.Info> getLocks() { 1326 String queryString = new QueryStringBuilder().appendParam("folder_id", this.getID()).toString(); 1327 final BoxAPIConnection api = this.getAPI(); 1328 return new BoxResourceIterable<BoxFolderLock.Info>(api, 1329 FOLDER_LOCK_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), queryString), 100) { 1330 @Override 1331 protected BoxFolderLock.Info factory(JsonObject jsonObject) { 1332 BoxFolderLock folderLock = 1333 new BoxFolderLock(api, jsonObject.get("id").asString()); 1334 return folderLock.new Info(jsonObject); 1335 } 1336 }; 1337 } 1338 1339 /** 1340 * Used to specify what direction to sort and display results. 1341 */ 1342 public enum SortDirection { 1343 /** 1344 * ASC for ascending order. 1345 */ 1346 ASC, 1347 1348 /** 1349 * DESC for descending order. 1350 */ 1351 DESC 1352 } 1353 1354 /** 1355 * Enumerates the possible sync states that a folder can have. 1356 */ 1357 public enum SyncState { 1358 /** 1359 * The folder is synced. 1360 */ 1361 SYNCED("synced"), 1362 1363 /** 1364 * The folder is not synced. 1365 */ 1366 NOT_SYNCED("not_synced"), 1367 1368 /** 1369 * The folder is partially synced. 1370 */ 1371 PARTIALLY_SYNCED("partially_synced"); 1372 1373 private final String jsonValue; 1374 1375 SyncState(String jsonValue) { 1376 this.jsonValue = jsonValue; 1377 } 1378 1379 static SyncState fromJSONValue(String jsonValue) { 1380 return SyncState.valueOf(jsonValue.toUpperCase()); 1381 } 1382 1383 String toJSONValue() { 1384 return this.jsonValue; 1385 } 1386 } 1387 1388 /** 1389 * Enumerates the possible permissions that a user can have on a folder. 1390 */ 1391 public enum Permission { 1392 /** 1393 * The user can download the folder. 1394 */ 1395 CAN_DOWNLOAD("can_download"), 1396 1397 /** 1398 * The user can upload to the folder. 1399 */ 1400 CAN_UPLOAD("can_upload"), 1401 1402 /** 1403 * The user can rename the folder. 1404 */ 1405 CAN_RENAME("can_rename"), 1406 1407 /** 1408 * The user can delete the folder. 1409 */ 1410 CAN_DELETE("can_delete"), 1411 1412 /** 1413 * The user can share the folder. 1414 */ 1415 CAN_SHARE("can_share"), 1416 1417 /** 1418 * The user can invite collaborators to the folder. 1419 */ 1420 CAN_INVITE_COLLABORATOR("can_invite_collaborator"), 1421 1422 /** 1423 * The user can set the access level for shared links to the folder. 1424 */ 1425 CAN_SET_SHARE_ACCESS("can_set_share_access"); 1426 1427 private final String jsonValue; 1428 1429 Permission(String jsonValue) { 1430 this.jsonValue = jsonValue; 1431 } 1432 1433 static Permission fromJSONValue(String jsonValue) { 1434 return Permission.valueOf(jsonValue.toUpperCase()); 1435 } 1436 1437 String toJSONValue() { 1438 return this.jsonValue; 1439 } 1440 } 1441 1442 /** 1443 * Contains information about a BoxFolder. 1444 */ 1445 public class Info extends BoxItem.Info { 1446 private BoxUploadEmail uploadEmail; 1447 private boolean hasCollaborations; 1448 private SyncState syncState; 1449 private EnumSet<Permission> permissions; 1450 private boolean canNonOwnersInvite; 1451 private boolean isWatermarked; 1452 private boolean isCollaborationRestrictedToEnterprise; 1453 private boolean isExternallyOwned; 1454 private Map<String, Map<String, Metadata>> metadataMap; 1455 private List<String> allowedSharedLinkAccessLevels; 1456 private List<String> allowedInviteeRoles; 1457 private BoxClassification classification; 1458 1459 /** 1460 * Constructs an empty Info object. 1461 */ 1462 public Info() { 1463 super(); 1464 } 1465 1466 /** 1467 * Constructs an Info object by parsing information from a JSON string. 1468 * 1469 * @param json the JSON string to parse. 1470 */ 1471 public Info(String json) { 1472 super(json); 1473 } 1474 1475 /** 1476 * Constructs an Info object using an already parsed JSON object. 1477 * 1478 * @param jsonObject the parsed JSON object. 1479 */ 1480 public Info(JsonObject jsonObject) { 1481 super(jsonObject); 1482 } 1483 1484 /** 1485 * Gets the upload email for the folder. 1486 * 1487 * @return the upload email for the folder. 1488 */ 1489 public BoxUploadEmail getUploadEmail() { 1490 return this.uploadEmail; 1491 } 1492 1493 /** 1494 * Sets the upload email for the folder. 1495 * 1496 * @param uploadEmail the upload email for the folder. 1497 */ 1498 public void setUploadEmail(BoxUploadEmail uploadEmail) { 1499 if (this.uploadEmail == uploadEmail) { 1500 return; 1501 } 1502 1503 this.removeChildObject("folder_upload_email"); 1504 this.uploadEmail = uploadEmail; 1505 1506 if (uploadEmail == null) { 1507 this.addPendingChange("folder_upload_email", (String) null); 1508 } else { 1509 this.addChildObject("folder_upload_email", uploadEmail); 1510 } 1511 } 1512 1513 /** 1514 * Gets whether or not the folder has any collaborations. 1515 * 1516 * @return true if the folder has collaborations; otherwise false. 1517 */ 1518 public boolean getHasCollaborations() { 1519 return this.hasCollaborations; 1520 } 1521 1522 /** 1523 * Gets the sync state of the folder. 1524 * 1525 * @return the sync state of the folder. 1526 */ 1527 public SyncState getSyncState() { 1528 return this.syncState; 1529 } 1530 1531 /** 1532 * Sets the sync state of the folder. 1533 * 1534 * @param syncState the sync state of the folder. 1535 */ 1536 public void setSyncState(SyncState syncState) { 1537 this.syncState = syncState; 1538 this.addPendingChange("sync_state", syncState.toJSONValue()); 1539 } 1540 1541 /** 1542 * Gets the permissions that the current user has on the folder. 1543 * 1544 * @return the permissions that the current user has on the folder. 1545 */ 1546 public EnumSet<Permission> getPermissions() { 1547 return this.permissions; 1548 } 1549 1550 /** 1551 * Gets whether or not the non-owners can invite collaborators to the folder. 1552 * 1553 * @return [description] 1554 */ 1555 public boolean getCanNonOwnersInvite() { 1556 return this.canNonOwnersInvite; 1557 } 1558 1559 /** 1560 * Sets whether or not non-owners can invite collaborators to the folder. 1561 * 1562 * @param canNonOwnersInvite indicates non-owners can invite collaborators to the folder. 1563 */ 1564 public void setCanNonOwnersInvite(boolean canNonOwnersInvite) { 1565 this.canNonOwnersInvite = canNonOwnersInvite; 1566 this.addPendingChange("can_non_owners_invite", canNonOwnersInvite); 1567 } 1568 1569 /** 1570 * Gets whether future collaborations should be restricted to within the enterprise only. 1571 * 1572 * @return indicates whether collaboration is restricted to enterprise only. 1573 */ 1574 public boolean getIsCollaborationRestrictedToEnterprise() { 1575 return this.isCollaborationRestrictedToEnterprise; 1576 } 1577 1578 /** 1579 * Sets whether future collaborations should be restricted to within the enterprise only. 1580 * 1581 * @param isRestricted indicates whether there is collaboration restriction within enterprise. 1582 */ 1583 public void setIsCollaborationRestrictedToEnterprise(boolean isRestricted) { 1584 this.isCollaborationRestrictedToEnterprise = isRestricted; 1585 this.addPendingChange("is_collaboration_restricted_to_enterprise", isRestricted); 1586 } 1587 1588 /** 1589 * Retrieves the allowed roles for collaborations. 1590 * 1591 * @return the roles allowed for collaboration. 1592 */ 1593 public List<String> getAllowedInviteeRoles() { 1594 return this.allowedInviteeRoles; 1595 } 1596 1597 /** 1598 * Retrieves the allowed access levels for a shared link. 1599 * 1600 * @return the allowed access levels for a shared link. 1601 */ 1602 public List<String> getAllowedSharedLinkAccessLevels() { 1603 return this.allowedSharedLinkAccessLevels; 1604 } 1605 1606 /** 1607 * Gets flag indicating whether this file is Watermarked. 1608 * 1609 * @return whether the file is watermarked or not 1610 */ 1611 public boolean getIsWatermarked() { 1612 return this.isWatermarked; 1613 } 1614 1615 /** 1616 * Gets the metadata on this folder associated with a specified scope and template. 1617 * Makes an attempt to get metadata that was retrieved using getInfo(String ...) method. 1618 * 1619 * @param templateName the metadata template type name. 1620 * @param scope the scope of the template (usually "global" or "enterprise"). 1621 * @return the metadata returned from the server. 1622 */ 1623 public Metadata getMetadata(String templateName, String scope) { 1624 try { 1625 return this.metadataMap.get(scope).get(templateName); 1626 } catch (NullPointerException e) { 1627 return null; 1628 } 1629 } 1630 1631 /** 1632 * Get the field is_externally_owned determining whether this folder is owned by a user outside of the 1633 * enterprise. 1634 * 1635 * @return a boolean indicating whether this folder is owned by a user outside the enterprise. 1636 */ 1637 public boolean getIsExternallyOwned() { 1638 return this.isExternallyOwned; 1639 } 1640 1641 /** 1642 * Gets the metadata classification type of this folder. 1643 * 1644 * @return the metadata classification type of this folder. 1645 */ 1646 public BoxClassification getClassification() { 1647 return this.classification; 1648 } 1649 1650 @Override 1651 public BoxFolder getResource() { 1652 return BoxFolder.this; 1653 } 1654 1655 @Override 1656 protected void parseJSONMember(JsonObject.Member member) { 1657 super.parseJSONMember(member); 1658 1659 String memberName = member.getName(); 1660 JsonValue value = member.getValue(); 1661 try { 1662 if (memberName.equals("folder_upload_email")) { 1663 if (this.uploadEmail == null) { 1664 this.uploadEmail = new BoxUploadEmail(value.asObject()); 1665 } else { 1666 this.uploadEmail.update(value.asObject()); 1667 } 1668 1669 } else if (memberName.equals("has_collaborations")) { 1670 this.hasCollaborations = value.asBoolean(); 1671 1672 } else if (memberName.equals("sync_state")) { 1673 this.syncState = SyncState.fromJSONValue(value.asString()); 1674 1675 } else if (memberName.equals("permissions")) { 1676 this.permissions = this.parsePermissions(value.asObject()); 1677 1678 } else if (memberName.equals("can_non_owners_invite")) { 1679 this.canNonOwnersInvite = value.asBoolean(); 1680 } else if (memberName.equals("allowed_shared_link_access_levels")) { 1681 this.allowedSharedLinkAccessLevels = this.parseSharedLinkAccessLevels(value.asArray()); 1682 } else if (memberName.equals("allowed_invitee_roles")) { 1683 this.allowedInviteeRoles = this.parseAllowedInviteeRoles(value.asArray()); 1684 } else if (memberName.equals("is_collaboration_restricted_to_enterprise")) { 1685 this.isCollaborationRestrictedToEnterprise = value.asBoolean(); 1686 } else if (memberName.equals("is_externally_owned")) { 1687 this.isExternallyOwned = value.asBoolean(); 1688 } else if (memberName.equals("watermark_info")) { 1689 JsonObject jsonObject = value.asObject(); 1690 this.isWatermarked = jsonObject.get("is_watermarked").asBoolean(); 1691 } else if (memberName.equals("metadata")) { 1692 JsonObject jsonObject = value.asObject(); 1693 this.metadataMap = Parsers.parseAndPopulateMetadataMap(jsonObject); 1694 } else if (memberName.equals("classification")) { 1695 if (value.isNull()) { 1696 this.classification = null; 1697 } else { 1698 this.classification = new BoxClassification(value.asObject()); 1699 } 1700 } 1701 } catch (Exception e) { 1702 throw new BoxDeserializationException(memberName, value.toString(), e); 1703 } 1704 } 1705 1706 private EnumSet<Permission> parsePermissions(JsonObject jsonObject) { 1707 EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class); 1708 for (JsonObject.Member member : jsonObject) { 1709 JsonValue value = member.getValue(); 1710 if (value.isNull() || !value.asBoolean()) { 1711 continue; 1712 } 1713 1714 String memberName = member.getName(); 1715 if (memberName.equals("can_download")) { 1716 permissions.add(Permission.CAN_DOWNLOAD); 1717 } else if (memberName.equals("can_upload")) { 1718 permissions.add(Permission.CAN_UPLOAD); 1719 } else if (memberName.equals("can_rename")) { 1720 permissions.add(Permission.CAN_RENAME); 1721 } else if (memberName.equals("can_delete")) { 1722 permissions.add(Permission.CAN_DELETE); 1723 } else if (memberName.equals("can_share")) { 1724 permissions.add(Permission.CAN_SHARE); 1725 } else if (memberName.equals("can_invite_collaborator")) { 1726 permissions.add(Permission.CAN_INVITE_COLLABORATOR); 1727 } else if (memberName.equals("can_set_share_access")) { 1728 permissions.add(Permission.CAN_SET_SHARE_ACCESS); 1729 } 1730 } 1731 1732 return permissions; 1733 } 1734 1735 private List<String> parseSharedLinkAccessLevels(JsonArray jsonArray) { 1736 List<String> accessLevels = new ArrayList<>(jsonArray.size()); 1737 for (JsonValue value : jsonArray) { 1738 accessLevels.add(value.asString()); 1739 } 1740 1741 return accessLevels; 1742 } 1743 1744 private List<String> parseAllowedInviteeRoles(JsonArray jsonArray) { 1745 List<String> roles = new ArrayList<>(jsonArray.size()); 1746 for (JsonValue value : jsonArray) { 1747 roles.add(value.asString()); 1748 } 1749 1750 return roles; 1751 } 1752 } 1753}