001package com.box.sdk; 002 003import java.io.IOException; 004import java.io.InputStream; 005import java.net.URL; 006import java.util.ArrayList; 007import java.util.Collection; 008import java.util.Date; 009import java.util.EnumSet; 010import java.util.Iterator; 011import java.util.concurrent.TimeUnit; 012 013import com.eclipsesource.json.JsonArray; 014import com.eclipsesource.json.JsonObject; 015import com.eclipsesource.json.JsonValue; 016 017/** 018 * Represents a folder on Box. This class can be used to iterate through a folder's contents, collaborate a folder with 019 * another user or group, and perform other common folder operations (move, copy, delete, etc.). 020 * 021 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 022 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 023 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p> 024 */ 025@BoxResourceType("folder") 026public class BoxFolder extends BoxItem implements Iterable<BoxItem.Info> { 027 /** 028 * An array of all possible folder fields that can be requested when calling {@link #getInfo()}. 029 */ 030 public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "name", "created_at", "modified_at", 031 "description", "size", "path_collection", "created_by", "modified_by", "trashed_at", "purged_at", 032 "content_created_at", "content_modified_at", "owned_by", "shared_link", "folder_upload_email", "parent", 033 "item_status", "item_collection", "sync_state", "has_collaborations", "permissions", "tags", 034 "can_non_owners_invite", "collections", "watermark_info"}; 035 036 private static final URLTemplate CREATE_FOLDER_URL = new URLTemplate("folders"); 037 private static final URLTemplate CREATE_WEB_LINK_URL = new URLTemplate("web_links"); 038 private static final URLTemplate COPY_FOLDER_URL = new URLTemplate("folders/%s/copy"); 039 private static final URLTemplate DELETE_FOLDER_URL = new URLTemplate("folders/%s?recursive=%b"); 040 private static final URLTemplate FOLDER_INFO_URL_TEMPLATE = new URLTemplate("folders/%s"); 041 private static final URLTemplate UPLOAD_FILE_URL = new URLTemplate("files/content"); 042 private static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations"); 043 private static final URLTemplate GET_COLLABORATIONS_URL = new URLTemplate("folders/%s/collaborations"); 044 private static final URLTemplate GET_ITEMS_URL = new URLTemplate("folders/%s/items/"); 045 private static final URLTemplate SEARCH_URL_TEMPLATE = new URLTemplate("search"); 046 private static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("folders/%s/metadata/%s/%s"); 047 private static final URLTemplate UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/upload_sessions"); 048 049 /** 050 * Constructs a BoxFolder for a folder with a given ID. 051 * @param api the API connection to be used by the folder. 052 * @param id the ID of the folder. 053 */ 054 public BoxFolder(BoxAPIConnection api, String id) { 055 super(api, id); 056 } 057 058 /** 059 * {@inheritDoc} 060 */ 061 @Override 062 protected URL getItemURL() { 063 return FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 064 } 065 066 /** 067 * Gets the current user's root folder. 068 * @param api the API connection to be used by the folder. 069 * @return the user's root folder. 070 */ 071 public static BoxFolder getRootFolder(BoxAPIConnection api) { 072 return new BoxFolder(api, "0"); 073 } 074 075 /** 076 * Adds a collaborator to this folder. 077 * @param collaborator the collaborator to add. 078 * @param role the role of the collaborator. 079 * @return info about the new collaboration. 080 */ 081 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role) { 082 JsonObject accessibleByField = new JsonObject(); 083 accessibleByField.add("id", collaborator.getID()); 084 085 if (collaborator instanceof BoxUser) { 086 accessibleByField.add("type", "user"); 087 } else if (collaborator instanceof BoxGroup) { 088 accessibleByField.add("type", "group"); 089 } else { 090 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 091 } 092 093 return this.collaborate(accessibleByField, role); 094 } 095 096 /** 097 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 098 * account. 099 * @param email the email address of the collaborator to add. 100 * @param role the role of the collaborator. 101 * @return info about the new collaboration. 102 */ 103 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role) { 104 JsonObject accessibleByField = new JsonObject(); 105 accessibleByField.add("login", email); 106 accessibleByField.add("type", "user"); 107 108 return this.collaborate(accessibleByField, role); 109 } 110 111 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role) { 112 BoxAPIConnection api = this.getAPI(); 113 URL url = ADD_COLLABORATION_URL.build(api.getBaseURL()); 114 115 JsonObject itemField = new JsonObject(); 116 itemField.add("id", this.getID()); 117 itemField.add("type", "folder"); 118 119 JsonObject requestJSON = new JsonObject(); 120 requestJSON.add("item", itemField); 121 requestJSON.add("accessible_by", accessibleByField); 122 requestJSON.add("role", role.toJSONString()); 123 124 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 125 request.setBody(requestJSON.toString()); 126 BoxJSONResponse response = (BoxJSONResponse) request.send(); 127 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 128 129 BoxCollaboration newCollaboration = new BoxCollaboration(api, responseJSON.get("id").asString()); 130 BoxCollaboration.Info info = newCollaboration.new Info(responseJSON); 131 return info; 132 } 133 /** 134 * Adds a collaborator to this folder. 135 * @param collaborator the collaborator to add. 136 * @param role the role of the collaborator. 137 * @param notify the user/group should receive email notification of the collaboration or not. 138 * @param canViewPath the view path collaboration feature is enabled or not. 139 * View path collaborations allow the invitee to see the entire ancestral path to the associated folder. 140 * The user will not gain privileges in any ancestral folder. 141 * @return info about the new collaboration. 142 */ 143 public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role, 144 Boolean notify, Boolean canViewPath) { 145 JsonObject accessibleByField = new JsonObject(); 146 accessibleByField.add("id", collaborator.getID()); 147 148 if (collaborator instanceof BoxUser) { 149 accessibleByField.add("type", "user"); 150 } else if (collaborator instanceof BoxGroup) { 151 accessibleByField.add("type", "group"); 152 } else { 153 throw new IllegalArgumentException("The given collaborator is of an unknown type."); 154 } 155 156 return this.collaborate(accessibleByField, role, notify, canViewPath); 157 } 158 159 /** 160 * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box 161 * account. 162 * @param email the email address of the collaborator to add. 163 * @param role the role of the collaborator. 164 * @param notify the user/group should receive email notification of the collaboration or not. 165 * @param canViewPath the view path collaboration feature is enabled or not. 166 * View path collaborations allow the invitee to see the entire ancestral path to the associated folder. 167 * The user will not gain privileges in any ancestral folder. 168 * @return info about the new collaboration. 169 */ 170 public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role, 171 Boolean notify, Boolean canViewPath) { 172 JsonObject accessibleByField = new JsonObject(); 173 accessibleByField.add("login", email); 174 accessibleByField.add("type", "user"); 175 176 return this.collaborate(accessibleByField, role, notify, canViewPath); 177 } 178 179 private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role, 180 Boolean notify, Boolean canViewPath) { 181 BoxAPIConnection api = this.getAPI(); 182 URL url = ADD_COLLABORATION_URL.build(api.getBaseURL()); 183 184 JsonObject itemField = new JsonObject(); 185 itemField.add("id", this.getID()); 186 itemField.add("type", "folder"); 187 188 JsonObject requestJSON = new JsonObject(); 189 requestJSON.add("item", itemField); 190 requestJSON.add("accessible_by", accessibleByField); 191 requestJSON.add("role", role.toJSONString()); 192 if (canViewPath != null) { 193 requestJSON.add("can_view_path", canViewPath.booleanValue()); 194 } 195 196 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 197 if (notify != null) { 198 request.addHeader("notify", notify.toString()); 199 } 200 201 request.setBody(requestJSON.toString()); 202 BoxJSONResponse response = (BoxJSONResponse) request.send(); 203 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 204 205 BoxCollaboration newCollaboration = new BoxCollaboration(api, responseJSON.get("id").asString()); 206 BoxCollaboration.Info info = newCollaboration.new Info(responseJSON); 207 return info; 208 } 209 210 @Override 211 public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 212 BoxSharedLink.Permissions permissions) { 213 214 BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions); 215 Info info = new Info(); 216 info.setSharedLink(sharedLink); 217 218 this.updateInfo(info); 219 return info.getSharedLink(); 220 } 221 222 /** 223 * Gets information about all of the collaborations for this folder. 224 * @return a collection of information about the collaborations for this folder. 225 */ 226 public Collection<BoxCollaboration.Info> getCollaborations() { 227 BoxAPIConnection api = this.getAPI(); 228 URL url = GET_COLLABORATIONS_URL.build(api.getBaseURL(), this.getID()); 229 230 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 231 BoxJSONResponse response = (BoxJSONResponse) request.send(); 232 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 233 234 int entriesCount = responseJSON.get("total_count").asInt(); 235 Collection<BoxCollaboration.Info> collaborations = new ArrayList<BoxCollaboration.Info>(entriesCount); 236 JsonArray entries = responseJSON.get("entries").asArray(); 237 for (JsonValue entry : entries) { 238 JsonObject entryObject = entry.asObject(); 239 BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString()); 240 BoxCollaboration.Info info = collaboration.new Info(entryObject); 241 collaborations.add(info); 242 } 243 244 return collaborations; 245 } 246 247 248 249 @Override 250 public BoxFolder.Info getInfo() { 251 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 252 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 253 BoxJSONResponse response = (BoxJSONResponse) request.send(); 254 return new Info(response.getJSON()); 255 } 256 257 @Override 258 public BoxFolder.Info getInfo(String... fields) { 259 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 260 URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 261 262 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 263 BoxJSONResponse response = (BoxJSONResponse) request.send(); 264 return new Info(response.getJSON()); 265 } 266 267 /** 268 * Updates the information about this folder with any info fields that have been modified locally. 269 * @param info the updated info. 270 */ 271 public void updateInfo(BoxFolder.Info info) { 272 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 273 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 274 request.setBody(info.getPendingChanges()); 275 BoxJSONResponse response = (BoxJSONResponse) request.send(); 276 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 277 info.update(jsonObject); 278 } 279 280 @Override 281 public BoxFolder.Info copy(BoxFolder destination) { 282 return this.copy(destination, null); 283 } 284 285 @Override 286 public BoxFolder.Info copy(BoxFolder destination, String newName) { 287 URL url = COPY_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID()); 288 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 289 290 JsonObject parent = new JsonObject(); 291 parent.add("id", destination.getID()); 292 293 JsonObject copyInfo = new JsonObject(); 294 copyInfo.add("parent", parent); 295 if (newName != null) { 296 copyInfo.add("name", newName); 297 } 298 299 request.setBody(copyInfo.toString()); 300 BoxJSONResponse response = (BoxJSONResponse) request.send(); 301 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 302 BoxFolder copiedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 303 return copiedFolder.new Info(responseJSON); 304 } 305 306 /** 307 * Creates a new child folder inside this folder. 308 * @param name the new folder's name. 309 * @return the created folder's info. 310 */ 311 public BoxFolder.Info createFolder(String name) { 312 JsonObject parent = new JsonObject(); 313 parent.add("id", this.getID()); 314 315 JsonObject newFolder = new JsonObject(); 316 newFolder.add("name", name); 317 newFolder.add("parent", parent); 318 319 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), CREATE_FOLDER_URL.build(this.getAPI().getBaseURL()), 320 "POST"); 321 request.setBody(newFolder.toString()); 322 BoxJSONResponse response = (BoxJSONResponse) request.send(); 323 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 324 325 BoxFolder createdFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 326 return createdFolder.new Info(responseJSON); 327 } 328 329 /** 330 * Deletes this folder, optionally recursively deleting all of its contents. 331 * @param recursive true to recursively delete this folder's contents; otherwise false. 332 */ 333 public void delete(boolean recursive) { 334 URL url = DELETE_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID(), recursive); 335 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 336 BoxAPIResponse response = request.send(); 337 response.disconnect(); 338 } 339 340 @Override 341 public BoxItem.Info move(BoxFolder destination) { 342 return this.move(destination, null); 343 } 344 345 @Override 346 public BoxItem.Info move(BoxFolder destination, String newName) { 347 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 348 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 349 350 JsonObject parent = new JsonObject(); 351 parent.add("id", destination.getID()); 352 353 JsonObject updateInfo = new JsonObject(); 354 updateInfo.add("parent", parent); 355 if (newName != null) { 356 updateInfo.add("name", newName); 357 } 358 359 request.setBody(updateInfo.toString()); 360 BoxJSONResponse response = (BoxJSONResponse) request.send(); 361 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 362 BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString()); 363 return movedFolder.new Info(responseJSON); 364 } 365 366 /** 367 * Renames this folder. 368 * @param newName the new name of the folder. 369 */ 370 public void rename(String newName) { 371 URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 372 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 373 374 JsonObject updateInfo = new JsonObject(); 375 updateInfo.add("name", newName); 376 377 request.setBody(updateInfo.toString()); 378 BoxJSONResponse response = (BoxJSONResponse) request.send(); 379 response.getJSON(); 380 } 381 382 /** 383 * Checks if the file can be successfully uploaded by using the preflight check. 384 * @param name the name to give the uploaded file. 385 * @param fileSize the size of the file used for account capacity calculations. 386 */ 387 public void canUpload(String name, long fileSize) { 388 URL url = UPLOAD_FILE_URL.build(this.getAPI().getBaseURL()); 389 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS"); 390 391 JsonObject parent = new JsonObject(); 392 parent.add("id", this.getID()); 393 394 JsonObject preflightInfo = new JsonObject(); 395 preflightInfo.add("parent", parent); 396 preflightInfo.add("name", name); 397 398 preflightInfo.add("size", fileSize); 399 400 request.setBody(preflightInfo.toString()); 401 BoxAPIResponse response = request.send(); 402 response.disconnect(); 403 } 404 405 /** 406 * Uploads a new file to this folder. 407 * @param fileContent a stream containing the contents of the file to upload. 408 * @param name the name to give the uploaded file. 409 * @return the uploaded file's info. 410 */ 411 public BoxFile.Info uploadFile(InputStream fileContent, String name) { 412 FileUploadParams uploadInfo = new FileUploadParams() 413 .setContent(fileContent) 414 .setName(name); 415 return this.uploadFile(uploadInfo); 416 } 417 418 /** 419 * Uploads a new file to this folder while reporting the progress to a ProgressListener. 420 * @param fileContent a stream containing the contents of the file to upload. 421 * @param name the name to give the uploaded file. 422 * @param fileSize the size of the file used for determining the progress of the upload. 423 * @param listener a listener for monitoring the upload's progress. 424 * @return the uploaded file's info. 425 */ 426 public BoxFile.Info uploadFile(InputStream fileContent, String name, long fileSize, ProgressListener listener) { 427 FileUploadParams uploadInfo = new FileUploadParams() 428 .setContent(fileContent) 429 .setName(name) 430 .setSize(fileSize) 431 .setProgressListener(listener); 432 return this.uploadFile(uploadInfo); 433 } 434 435 /** 436 * Uploads a new file to this folder with custom upload parameters. 437 * @param uploadParams the custom upload parameters. 438 * @return the uploaded file's info. 439 */ 440 public BoxFile.Info uploadFile(FileUploadParams uploadParams) { 441 URL uploadURL = UPLOAD_FILE_URL.build(this.getAPI().getBaseUploadURL()); 442 BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL); 443 444 JsonObject fieldJSON = new JsonObject(); 445 JsonObject parentIdJSON = new JsonObject(); 446 parentIdJSON.add("id", getID()); 447 fieldJSON.add("name", uploadParams.getName()); 448 fieldJSON.add("parent", parentIdJSON); 449 450 if (uploadParams.getCreated() != null) { 451 fieldJSON.add("content_created_at", BoxDateFormat.format(uploadParams.getCreated())); 452 } 453 454 if (uploadParams.getModified() != null) { 455 fieldJSON.add("content_modified_at", BoxDateFormat.format(uploadParams.getModified())); 456 } 457 458 request.putField("attributes", fieldJSON.toString()); 459 460 if (uploadParams.getSize() > 0) { 461 request.setFile(uploadParams.getContent(), uploadParams.getName(), uploadParams.getSize()); 462 } else { 463 request.setFile(uploadParams.getContent(), uploadParams.getName()); 464 } 465 466 BoxJSONResponse response; 467 if (uploadParams.getProgressListener() == null) { 468 response = (BoxJSONResponse) request.send(); 469 } else { 470 response = (BoxJSONResponse) request.send(uploadParams.getProgressListener()); 471 } 472 JsonObject collection = JsonObject.readFrom(response.getJSON()); 473 JsonArray entries = collection.get("entries").asArray(); 474 JsonObject fileInfoJSON = entries.get(0).asObject(); 475 String uploadedFileID = fileInfoJSON.get("id").asString(); 476 477 BoxFile uploadedFile = new BoxFile(getAPI(), uploadedFileID); 478 return uploadedFile.new Info(fileInfoJSON); 479 } 480 481 /** 482 * Uploads a new weblink to this folder. 483 * @param linkURL the URL the weblink points to. 484 * @return the uploaded weblink's info. 485 */ 486 public BoxWebLink.Info createWebLink(URL linkURL) { 487 return this.createWebLink(null, linkURL, null); 488 } 489 490 /** 491 * Uploads a new weblink to this folder. 492 * @param name the filename for the weblink. 493 * @param linkURL the URL the weblink points to. 494 * @return the uploaded weblink's info. 495 */ 496 public BoxWebLink.Info createWebLink(String name, URL linkURL) { 497 return this.createWebLink(name, linkURL, null); 498 } 499 500 /** 501 * Uploads a new weblink to this folder. 502 * @param linkURL the URL the weblink points to. 503 * @param description the weblink's description. 504 * @return the uploaded weblink's info. 505 */ 506 public BoxWebLink.Info createWebLink(URL linkURL, String description) { 507 return this.createWebLink(null, linkURL, description); 508 } 509 510 /** 511 * Uploads a new weblink to this folder. 512 * @param name the filename for the weblink. 513 * @param linkURL the URL the weblink points to. 514 * @param description the weblink's description. 515 * @return the uploaded weblink's info. 516 */ 517 public BoxWebLink.Info createWebLink(String name, URL linkURL, String description) { 518 JsonObject parent = new JsonObject(); 519 parent.add("id", this.getID()); 520 521 JsonObject newWebLink = new JsonObject(); 522 newWebLink.add("name", name); 523 newWebLink.add("parent", parent); 524 newWebLink.add("url", linkURL.toString()); 525 526 if (description != null) { 527 newWebLink.add("description", description); 528 } 529 530 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), 531 CREATE_WEB_LINK_URL.build(this.getAPI().getBaseURL()), "POST"); 532 request.setBody(newWebLink.toString()); 533 BoxJSONResponse response = (BoxJSONResponse) request.send(); 534 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 535 536 BoxWebLink createdWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString()); 537 return createdWebLink.new Info(responseJSON); 538 } 539 540 /** 541 * Returns an iterable containing the items in this folder. Iterating over the iterable returned by this method is 542 * equivalent to iterating over this BoxFolder directly. 543 * @return an iterable containing the items in this folder. 544 */ 545 public Iterable<BoxItem.Info> getChildren() { 546 return this; 547 } 548 549 /** 550 * Returns an iterable containing the items in this folder and specifies which child fields to retrieve from the 551 * API. 552 * @param fields the fields to retrieve. 553 * @return an iterable containing the items in this folder. 554 */ 555 public Iterable<BoxItem.Info> getChildren(final String... fields) { 556 return new Iterable<BoxItem.Info>() { 557 @Override 558 public Iterator<BoxItem.Info> iterator() { 559 String queryString = new QueryStringBuilder().appendParam("fields", fields).toString(); 560 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), queryString, getID()); 561 return new BoxItemIterator(getAPI(), url); 562 } 563 }; 564 } 565 566 /** 567 * Retrieves a specific range of child items in this folder. 568 * @param offset the index of the first child item to retrieve. 569 * @param limit the maximum number of children to retrieve after the offset. 570 * @param fields the fields to retrieve. 571 * @return a partial collection containing the specified range of child items. 572 */ 573 public PartialCollection<BoxItem.Info> getChildrenRange(long offset, long limit, String... fields) { 574 QueryStringBuilder builder = new QueryStringBuilder() 575 .appendParam("limit", limit) 576 .appendParam("offset", offset); 577 578 if (fields.length > 0) { 579 builder.appendParam("fields", fields).toString(); 580 } 581 582 URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), builder.toString(), getID()); 583 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 584 BoxJSONResponse response = (BoxJSONResponse) request.send(); 585 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 586 587 String totalCountString = responseJSON.get("total_count").toString(); 588 long fullSize = Double.valueOf(totalCountString).longValue(); 589 PartialCollection<BoxItem.Info> children = new PartialCollection<BoxItem.Info>(offset, limit, fullSize); 590 JsonArray jsonArray = responseJSON.get("entries").asArray(); 591 for (JsonValue value : jsonArray) { 592 JsonObject jsonObject = value.asObject(); 593 BoxItem.Info parsedItemInfo = (BoxItem.Info) BoxResource.parseInfo(this.getAPI(), jsonObject); 594 if (parsedItemInfo != null) { 595 children.add(parsedItemInfo); 596 } 597 } 598 return children; 599 } 600 601 /** 602 * Returns an iterator over the items in this folder. 603 * @return an iterator over the items in this folder. 604 */ 605 @Override 606 public Iterator<BoxItem.Info> iterator() { 607 URL url = GET_ITEMS_URL.build(this.getAPI().getBaseURL(), BoxFolder.this.getID()); 608 return new BoxItemIterator(BoxFolder.this.getAPI(), url); 609 } 610 611 /** 612 * Adds new {@link BoxWebHook} to this {@link BoxFolder}. 613 * 614 * @param address 615 * {@link BoxWebHook.Info#getAddress()} 616 * @param triggers 617 * {@link BoxWebHook.Info#getTriggers()} 618 * @return created {@link BoxWebHook.Info} 619 */ 620 public BoxWebHook.Info addWebHook(URL address, BoxWebHook.Trigger... triggers) { 621 return BoxWebHook.create(this, address, triggers); 622 } 623 624 /** 625 626 * Used to retrieve the watermark for the folder. 627 * If the folder does not have a watermark applied to it, a 404 Not Found will be returned by API. 628 * @param fields the fields to retrieve. 629 * @return the watermark associated with the folder. 630 */ 631 public BoxWatermark getWatermark(String... fields) { 632 return this.getWatermark(FOLDER_INFO_URL_TEMPLATE, fields); 633 } 634 635 /** 636 * Used to apply or update the watermark for the folder. 637 * @return the watermark associated with the folder. 638 */ 639 public BoxWatermark applyWatermark() { 640 return this.applyWatermark(FOLDER_INFO_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT); 641 } 642 643 /** 644 * Removes a watermark from the folder. 645 * If the folder did not have a watermark applied to it, a 404 Not Found will be returned by API. 646 */ 647 public void removeWatermark() { 648 this.removeWatermark(FOLDER_INFO_URL_TEMPLATE); 649 } 650 651 /** 652 * Used to retrieve all metadata associated with the folder. 653 * 654 * @param fields the optional fields to retrieve. 655 * @return An iterable of metadata instances associated with the folder 656 */ 657 public Iterable<Metadata> getAllMetadata(String... fields) { 658 return Metadata.getAllMetadata(this, fields); 659 } 660 661 /** 662 * This method is deprecated, please use the {@link BoxSearch} class instead. 663 * Searches this folder and all descendant folders using a given queryPlease use BoxSearch Instead. 664 * @param query the search query. 665 * @return an Iterable containing the search results. 666 */ 667 @Deprecated 668 public Iterable<BoxItem.Info> search(final String query) { 669 return new Iterable<BoxItem.Info>() { 670 @Override 671 public Iterator<BoxItem.Info> iterator() { 672 QueryStringBuilder builder = new QueryStringBuilder(); 673 builder.appendParam("query", query); 674 builder.appendParam("ancestor_folder_ids", getID()); 675 676 URL url = SEARCH_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), builder.toString()); 677 return new BoxItemIterator(getAPI(), url); 678 } 679 }; 680 } 681 682 @Override 683 public BoxFolder.Info setCollections(BoxCollection... collections) { 684 JsonArray jsonArray = new JsonArray(); 685 for (BoxCollection collection : collections) { 686 JsonObject collectionJSON = new JsonObject(); 687 collectionJSON.add("id", collection.getID()); 688 jsonArray.add(collectionJSON); 689 } 690 JsonObject infoJSON = new JsonObject(); 691 infoJSON.add("collections", jsonArray); 692 693 String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString(); 694 URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID()); 695 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 696 request.setBody(infoJSON.toString()); 697 BoxJSONResponse response = (BoxJSONResponse) request.send(); 698 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 699 return new Info(jsonObject); 700 } 701 702 /** 703 * Creates global property metadata on this folder. 704 * @param metadata the new metadata values. 705 * @return the metadata returned from the server. 706 */ 707 public Metadata createMetadata(Metadata metadata) { 708 return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata); 709 } 710 711 /** 712 * Creates metadata on this folder using a specified template. 713 * @param templateName the name of the metadata template. 714 * @param metadata the new metadata values. 715 * @return the metadata returned from the server. 716 */ 717 public Metadata createMetadata(String templateName, Metadata metadata) { 718 String scope = Metadata.scopeBasedOnType(templateName); 719 return this.createMetadata(templateName, scope, metadata); 720 } 721 722 /** 723 * Creates metadata on this folder using a specified scope and template. 724 * @param templateName the name of the metadata template. 725 * @param scope the scope of the template (usually "global" or "enterprise"). 726 * @param metadata the new metadata values. 727 * @return the metadata returned from the server. 728 */ 729 public Metadata createMetadata(String templateName, String scope, Metadata metadata) { 730 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 731 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "POST"); 732 request.addHeader("Content-Type", "application/json"); 733 request.setBody(metadata.toString()); 734 BoxJSONResponse response = (BoxJSONResponse) request.send(); 735 return new Metadata(JsonObject.readFrom(response.getJSON())); 736 } 737 738 /** 739 * Gets the global properties metadata on this folder. 740 * @return the metadata returned from the server. 741 */ 742 public Metadata getMetadata() { 743 return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE); 744 } 745 746 /** 747 * Gets the metadata on this folder associated with a specified template. 748 * @param templateName the metadata template type name. 749 * @return the metadata returned from the server. 750 */ 751 public Metadata getMetadata(String templateName) { 752 String scope = Metadata.scopeBasedOnType(templateName); 753 return this.getMetadata(templateName, scope); 754 } 755 756 /** 757 * Gets the metadata on this folder associated with a specified scope and template. 758 * @param templateName the metadata template type name. 759 * @param scope the scope of the template (usually "global" or "enterprise"). 760 * @return the metadata returned from the server. 761 */ 762 public Metadata getMetadata(String templateName, String scope) { 763 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 764 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 765 BoxJSONResponse response = (BoxJSONResponse) request.send(); 766 return new Metadata(JsonObject.readFrom(response.getJSON())); 767 } 768 769 /** 770 * Updates the global properties metadata on this folder. 771 * @param metadata the new metadata values. 772 * @return the metadata returned from the server. 773 */ 774 public Metadata updateMetadata(Metadata metadata) { 775 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), metadata.getScope(), 776 metadata.getTemplateName()); 777 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "PUT"); 778 request.addHeader("Content-Type", "application/json-patch+json"); 779 request.setBody(metadata.getPatch()); 780 BoxJSONResponse response = (BoxJSONResponse) request.send(); 781 return new Metadata(JsonObject.readFrom(response.getJSON())); 782 } 783 784 /** 785 * Deletes the global properties metadata on this folder. 786 */ 787 public void deleteMetadata() { 788 this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE); 789 } 790 791 /** 792 * Deletes the metadata on this folder associated with a specified template. 793 * @param templateName the metadata template type name. 794 */ 795 public void deleteMetadata(String templateName) { 796 String scope = Metadata.scopeBasedOnType(templateName); 797 this.deleteMetadata(templateName, scope); 798 } 799 800 /** 801 * Deletes the metadata on this folder associated with a specified scope and template. 802 * @param templateName the metadata template type name. 803 * @param scope the scope of the template (usually "global" or "enterprise"). 804 */ 805 public void deleteMetadata(String templateName, String scope) { 806 URL url = METADATA_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID(), scope, templateName); 807 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 808 BoxAPIResponse response = request.send(); 809 response.disconnect(); 810 } 811 812 /** 813 * Creates an upload session to create a new file in chunks. 814 * This will first verify that the file can be created and then open a session for uploading pieces of the file. 815 * @param fileName the name of the file to be created 816 * @param fileSize the size of the file that will be uploaded 817 * @return the created upload session instance 818 */ 819 public BoxFileUploadSession.Info createUploadSession(String fileName, long fileSize) { 820 821 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 822 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST"); 823 824 JsonObject body = new JsonObject(); 825 body.add("folder_id", this.getID()); 826 body.add("file_name", fileName); 827 body.add("file_size", fileSize); 828 request.setBody(body.toString()); 829 830 BoxJSONResponse response = (BoxJSONResponse) request.send(); 831 JsonObject jsonObject = JsonObject.readFrom(response.getJSON()); 832 833 String sessionId = jsonObject.get("id").asString(); 834 BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId); 835 836 return session.new Info(jsonObject); 837 } 838 839 /** 840 * Creates a new file. 841 * @param inputStream the stream instance that contains the data. 842 * @param fileName the name of the file to be created. 843 * @param fileSize the size of the file that will be uploaded. 844 * @return the created file instance. 845 * @throws InterruptedException when a thread execution is interrupted. 846 * @throws IOException when reading a stream throws exception. 847 */ 848 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize) 849 throws InterruptedException, IOException { 850 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 851 return new LargeFileUpload(). 852 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize); 853 } 854 855 /** 856 * Creates a new file using specified number of parallel http connections. 857 * @param inputStream the stream instance that contains the data. 858 * @param fileName the name of the file to be created. 859 * @param fileSize the size of the file that will be uploaded. 860 * @param nParallelConnections number of parallel http connections to use 861 * @param timeOut time to wait before killing the job 862 * @param unit time unit for the time wait value 863 * @return the created file instance. 864 * @throws InterruptedException when a thread execution is interrupted. 865 * @throws IOException when reading a stream throws exception. 866 */ 867 public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize, 868 int nParallelConnections, long timeOut, TimeUnit unit) 869 throws InterruptedException, IOException { 870 URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL()); 871 return new LargeFileUpload(nParallelConnections, timeOut, unit). 872 upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize); 873 } 874 875 /** 876 * Contains information about a BoxFolder. 877 */ 878 public class Info extends BoxItem.Info { 879 private BoxUploadEmail uploadEmail; 880 private boolean hasCollaborations; 881 private SyncState syncState; 882 private EnumSet<Permission> permissions; 883 private boolean canNonOwnersInvite; 884 private boolean isWatermarked; 885 886 /** 887 * Constructs an empty Info object. 888 */ 889 public Info() { 890 super(); 891 } 892 893 /** 894 * Constructs an Info object by parsing information from a JSON string. 895 * @param json the JSON string to parse. 896 */ 897 public Info(String json) { 898 super(json); 899 } 900 901 /** 902 * Constructs an Info object using an already parsed JSON object. 903 * @param jsonObject the parsed JSON object. 904 */ 905 Info(JsonObject jsonObject) { 906 super(jsonObject); 907 } 908 909 /** 910 * Gets the upload email for the folder. 911 * @return the upload email for the folder. 912 */ 913 public BoxUploadEmail getUploadEmail() { 914 return this.uploadEmail; 915 } 916 917 /** 918 * Sets the upload email for the folder. 919 * @param uploadEmail the upload email for the folder. 920 */ 921 public void setUploadEmail(BoxUploadEmail uploadEmail) { 922 if (this.uploadEmail == uploadEmail) { 923 return; 924 } 925 926 this.removeChildObject("folder_upload_email"); 927 this.uploadEmail = uploadEmail; 928 929 if (uploadEmail == null) { 930 this.addPendingChange("folder_upload_email", (String) null); 931 } else { 932 this.addChildObject("folder_upload_email", uploadEmail); 933 } 934 } 935 936 /** 937 * Gets whether or not the folder has any collaborations. 938 * @return true if the folder has collaborations; otherwise false. 939 */ 940 public boolean getHasCollaborations() { 941 return this.hasCollaborations; 942 } 943 944 /** 945 * Gets the sync state of the folder. 946 * @return the sync state of the folder. 947 */ 948 public SyncState getSyncState() { 949 return this.syncState; 950 } 951 952 /** 953 * Sets the sync state of the folder. 954 * @param syncState the sync state of the folder. 955 */ 956 public void setSyncState(SyncState syncState) { 957 this.syncState = syncState; 958 this.addPendingChange("sync_state", syncState.toJSONValue()); 959 } 960 961 /** 962 * Gets the permissions that the current user has on the folder. 963 * @return the permissions that the current user has on the folder. 964 */ 965 public EnumSet<Permission> getPermissions() { 966 return this.permissions; 967 } 968 969 /** 970 * Gets whether or not the non-owners can invite collaborators to the folder. 971 * @return [description] 972 */ 973 public boolean getCanNonOwnersInvite() { 974 return this.canNonOwnersInvite; 975 } 976 977 /** 978 * Gets flag indicating whether this file is Watermarked. 979 * @return whether the file is watermarked or not 980 */ 981 public boolean getIsWatermarked() { 982 return this.isWatermarked; 983 } 984 985 @Override 986 public BoxFolder getResource() { 987 return BoxFolder.this; 988 } 989 990 @Override 991 protected void parseJSONMember(JsonObject.Member member) { 992 super.parseJSONMember(member); 993 994 String memberName = member.getName(); 995 JsonValue value = member.getValue(); 996 if (memberName.equals("folder_upload_email")) { 997 if (this.uploadEmail == null) { 998 this.uploadEmail = new BoxUploadEmail(value.asObject()); 999 } else { 1000 this.uploadEmail.update(value.asObject()); 1001 } 1002 1003 } else if (memberName.equals("has_collaborations")) { 1004 this.hasCollaborations = value.asBoolean(); 1005 1006 } else if (memberName.equals("sync_state")) { 1007 this.syncState = SyncState.fromJSONValue(value.asString()); 1008 1009 } else if (memberName.equals("permissions")) { 1010 this.permissions = this.parsePermissions(value.asObject()); 1011 1012 } else if (memberName.equals("can_non_owners_invite")) { 1013 this.canNonOwnersInvite = value.asBoolean(); 1014 } else if (memberName.equals("watermark_info")) { 1015 JsonObject jsonObject = value.asObject(); 1016 this.isWatermarked = jsonObject.get("is_watermarked").asBoolean(); 1017 } 1018 } 1019 1020 private EnumSet<Permission> parsePermissions(JsonObject jsonObject) { 1021 EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class); 1022 for (JsonObject.Member member : jsonObject) { 1023 JsonValue value = member.getValue(); 1024 if (value.isNull() || !value.asBoolean()) { 1025 continue; 1026 } 1027 1028 String memberName = member.getName(); 1029 if (memberName.equals("can_download")) { 1030 permissions.add(Permission.CAN_DOWNLOAD); 1031 } else if (memberName.equals("can_upload")) { 1032 permissions.add(Permission.CAN_UPLOAD); 1033 } else if (memberName.equals("can_rename")) { 1034 permissions.add(Permission.CAN_RENAME); 1035 } else if (memberName.equals("can_delete")) { 1036 permissions.add(Permission.CAN_DELETE); 1037 } else if (memberName.equals("can_share")) { 1038 permissions.add(Permission.CAN_SHARE); 1039 } else if (memberName.equals("can_invite_collaborator")) { 1040 permissions.add(Permission.CAN_INVITE_COLLABORATOR); 1041 } else if (memberName.equals("can_set_share_access")) { 1042 permissions.add(Permission.CAN_SET_SHARE_ACCESS); 1043 } 1044 } 1045 1046 return permissions; 1047 } 1048 } 1049 1050 /** 1051 * Enumerates the possible sync states that a folder can have. 1052 */ 1053 public enum SyncState { 1054 /** 1055 * The folder is synced. 1056 */ 1057 SYNCED("synced"), 1058 1059 /** 1060 * The folder is not synced. 1061 */ 1062 NOT_SYNCED("not_synced"), 1063 1064 /** 1065 * The folder is partially synced. 1066 */ 1067 PARTIALLY_SYNCED("partially_synced"); 1068 1069 private final String jsonValue; 1070 1071 private SyncState(String jsonValue) { 1072 this.jsonValue = jsonValue; 1073 } 1074 1075 static SyncState fromJSONValue(String jsonValue) { 1076 return SyncState.valueOf(jsonValue.toUpperCase()); 1077 } 1078 1079 String toJSONValue() { 1080 return this.jsonValue; 1081 } 1082 } 1083 1084 /** 1085 * Enumerates the possible permissions that a user can have on a folder. 1086 */ 1087 public enum Permission { 1088 /** 1089 * The user can download the folder. 1090 */ 1091 CAN_DOWNLOAD("can_download"), 1092 1093 /** 1094 * The user can upload to the folder. 1095 */ 1096 CAN_UPLOAD("can_upload"), 1097 1098 /** 1099 * The user can rename the folder. 1100 */ 1101 CAN_RENAME("can_rename"), 1102 1103 /** 1104 * The user can delete the folder. 1105 */ 1106 CAN_DELETE("can_delete"), 1107 1108 /** 1109 * The user can share the folder. 1110 */ 1111 CAN_SHARE("can_share"), 1112 1113 /** 1114 * The user can invite collaborators to the folder. 1115 */ 1116 CAN_INVITE_COLLABORATOR("can_invite_collaborator"), 1117 1118 /** 1119 * The user can set the access level for shared links to the folder. 1120 */ 1121 CAN_SET_SHARE_ACCESS("can_set_share_access"); 1122 1123 private final String jsonValue; 1124 1125 private Permission(String jsonValue) { 1126 this.jsonValue = jsonValue; 1127 } 1128 1129 static Permission fromJSONValue(String jsonValue) { 1130 return Permission.valueOf(jsonValue.toUpperCase()); 1131 } 1132 1133 String toJSONValue() { 1134 return this.jsonValue; 1135 } 1136 } 1137}