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