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