001package com.box.sdk; 002 003import com.eclipsesource.json.Json; 004import com.eclipsesource.json.JsonArray; 005import com.eclipsesource.json.JsonObject; 006import com.eclipsesource.json.JsonValue; 007import java.net.URL; 008import java.util.ArrayList; 009import java.util.Date; 010import java.util.HashSet; 011import java.util.List; 012import java.util.Set; 013 014/** 015 * The abstract base class for items in a user's file tree (files, folders, etc.). 016 */ 017public abstract class BoxItem extends BoxResource { 018 /** 019 * An array of all possible file fields that can be requested when calling {@link #getInfo()}. 020 */ 021 public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "sha1", "name", "description", 022 "size", "path_collection", "created_at", "modified_at", "trashed_at", "purged_at", "content_created_at", 023 "content_modified_at", "created_by", "modified_by", "owned_by", "shared_link", "parent", "item_status", 024 "version_number", "comment_count", "permissions", "tags", "lock", "extension", "is_package", 025 "folder_upload_email", "item_collection", "sync_state", "has_collaborations", "can_non_owners_invite", 026 "file_version", "collections", "expires_at"}; 027 /** 028 * Shared Item URL Template. 029 */ 030 public static final URLTemplate SHARED_ITEM_URL_TEMPLATE = new URLTemplate("shared_items"); 031 032 /** 033 * Url template for operations with watermarks. 034 */ 035 public static final URLTemplate WATERMARK_URL_TEMPLATE = new URLTemplate("/watermark"); 036 037 /** 038 * Constructs a BoxItem for an item with a given ID. 039 * 040 * @param api the API connection to be used by the item. 041 * @param id the ID of the item. 042 */ 043 public BoxItem(BoxAPIConnection api, String id) { 044 super(api, id); 045 } 046 047 /** 048 * Gets an item that was shared with a shared link. 049 * 050 * @param api the API connection to be used by the shared item. 051 * @param sharedLink the shared link to the item. 052 * @return info about the shared item. 053 */ 054 public static BoxItem.Info getSharedItem(BoxAPIConnection api, String sharedLink) { 055 return getSharedItem(api, sharedLink, null); 056 } 057 058 /** 059 * Gets an item that was shared with a password-protected shared link. 060 * 061 * @param api the API connection to be used by the shared item. 062 * @param sharedLink the shared link to the item. 063 * @param password the password for the shared link. 064 * @return info about the shared item. 065 */ 066 public static BoxItem.Info getSharedItem(BoxAPIConnection api, String sharedLink, String password) { 067 BoxAPIConnection newAPI = new SharedLinkAPIConnection(api, sharedLink, password); 068 URL url = SHARED_ITEM_URL_TEMPLATE.build(newAPI.getBaseURL()); 069 BoxAPIRequest request = new BoxAPIRequest(newAPI, url, "GET"); 070 BoxJSONResponse response = (BoxJSONResponse) request.send(); 071 JsonObject json = Json.parse(response.getJSON()).asObject(); 072 return (BoxItem.Info) BoxResource.parseInfo(newAPI, json); 073 } 074 075 /** 076 * @return URL for the current object, constructed as base URL pus an item specifier. 077 */ 078 protected URL getItemURL() { 079 return new URLTemplate("").build(this.getAPI().getBaseURL()); 080 } 081 082 /** 083 * Used to retrieve the watermark for the item. 084 * If the item does not have a watermark applied to it, a 404 Not Found will be returned by API. 085 * 086 * @param itemUrl url template for the item. 087 * @param fields the fields to retrieve. 088 * @return the watermark associated with the item. 089 */ 090 protected BoxWatermark getWatermark(URLTemplate itemUrl, String... fields) { 091 URL watermarkUrl = itemUrl.build(this.getAPI().getBaseURL(), this.getID()); 092 QueryStringBuilder builder = new QueryStringBuilder(); 093 if (fields.length > 0) { 094 builder.appendParam("fields", fields); 095 } 096 URL url = WATERMARK_URL_TEMPLATE.buildWithQuery(watermarkUrl.toString(), builder.toString()); 097 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 098 BoxJSONResponse response = (BoxJSONResponse) request.send(); 099 return new BoxWatermark(response.getJSON()); 100 } 101 102 /** 103 * Used to apply or update the watermark for the item. 104 * 105 * @param itemUrl url template for the item. 106 * @param imprint the value must be "default", as custom watermarks is not yet supported. 107 * @return the watermark associated with the item. 108 */ 109 protected BoxWatermark applyWatermark(URLTemplate itemUrl, String imprint) { 110 URL watermarkUrl = itemUrl.build(this.getAPI().getBaseURL(), this.getID()); 111 URL url = WATERMARK_URL_TEMPLATE.build(watermarkUrl.toString()); 112 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 113 JsonObject body = new JsonObject() 114 .add(BoxWatermark.WATERMARK_JSON_KEY, new JsonObject() 115 .add(BoxWatermark.WATERMARK_IMPRINT_JSON_KEY, imprint)); 116 request.setBody(body.toString()); 117 BoxJSONResponse response = (BoxJSONResponse) request.send(); 118 return new BoxWatermark(response.getJSON()); 119 } 120 121 /** 122 * Removes a watermark from the item. 123 * If the item did not have a watermark applied to it, a 404 Not Found will be returned by API. 124 * 125 * @param itemUrl url template for the item. 126 */ 127 protected void removeWatermark(URLTemplate itemUrl) { 128 URL watermarkUrl = itemUrl.build(this.getAPI().getBaseURL(), this.getID()); 129 URL url = WATERMARK_URL_TEMPLATE.build(watermarkUrl.toString()); 130 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 131 BoxAPIResponse response = request.send(); 132 response.disconnect(); 133 } 134 135 /** 136 * Copies this item to another folder. 137 * 138 * @param destination the destination folder. 139 * @return info about the copied item. 140 */ 141 public abstract BoxItem.Info copy(BoxFolder destination); 142 143 /** 144 * Copies this item to another folder and gives it a new name. If the destination is the same folder as the item's 145 * current parent, then newName must be a new, unique name. 146 * 147 * @param destination the destination folder. 148 * @param newName a new name for the copied item. 149 * @return info about the copied item. 150 */ 151 public abstract BoxItem.Info copy(BoxFolder destination, String newName); 152 153 /** 154 * Moves this item to another folder. 155 * 156 * @param destination the destination folder. 157 * @return info about the moved item. 158 */ 159 public abstract BoxItem.Info move(BoxFolder destination); 160 161 /** 162 * Moves this item to another folder and gives it a new name. 163 * 164 * @param destination the destination folder. 165 * @param newName a new name for the moved item. 166 * @return info about the moved item. 167 */ 168 public abstract BoxItem.Info move(BoxFolder destination, String newName); 169 170 /** 171 * Creates a new shared link for this item. 172 * 173 * <p>This method is a convenience method for manually creating a new shared link and applying it to this item with 174 * {@link Info#setSharedLink}. You may want to create the shared link manually so that it can be updated along with 175 * other changes to the item's info in a single network request, giving a boost to performance.</p> 176 * 177 * @param access the access level of the shared link. 178 * @param unshareDate the date and time at which the link will expire. Can be null to create a non-expiring link. 179 * @param permissions the permissions of the shared link. Can be null to use the default permissions. 180 * @return the created shared link. 181 * @deprecated Use dedicated <code>createSharedLink(BoxSharedLinkRequest)</code> methods on subclasses to create BoxSharedLink 182 */ 183 @Deprecated 184 public abstract BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate, 185 BoxSharedLink.Permissions permissions); 186 187 /** 188 * Gets information about this item. 189 * 190 * @return info about this item. 191 */ 192 public abstract BoxItem.Info getInfo(); 193 194 /** 195 * Gets information about this item that's limited to a list of specified fields. 196 * 197 * @param fields the fields to retrieve. 198 * @return info about this item containing only the specified fields. 199 */ 200 public abstract BoxItem.Info getInfo(String... fields); 201 202 /** 203 * Sets the collections that this item belongs to. 204 * 205 * @param collections the collections that this item should belong to. 206 * @return info about the item, including the collections it belongs to. 207 */ 208 public abstract BoxItem.Info setCollections(BoxCollection... collections); 209 210 /** 211 * Contains information about a BoxItem. 212 */ 213 public abstract class Info extends BoxResource.Info { 214 private String type; 215 private String sequenceID; 216 private String etag; 217 private String name; 218 private Date createdAt; 219 private Date modifiedAt; 220 private String description; 221 private long size; 222 private List<BoxFolder.Info> pathCollection; 223 private BoxUser.Info createdBy; 224 private BoxUser.Info modifiedBy; 225 private Date trashedAt; 226 private Date purgedAt; 227 private Date contentCreatedAt; 228 private Date contentModifiedAt; 229 private BoxUser.Info ownedBy; 230 private BoxSharedLink sharedLink; 231 private List<String> tags; 232 private BoxFolder.Info parent; 233 private String itemStatus; 234 private Date expiresAt; 235 private Set<BoxCollection.Info> collections; 236 237 /** 238 * Constructs an empty Info object. 239 */ 240 public Info() { 241 super(); 242 } 243 244 /** 245 * Constructs an Info object by parsing information from a JSON string. 246 * 247 * @param json the JSON string to parse. 248 */ 249 public Info(String json) { 250 super(json); 251 } 252 253 /** 254 * Constructs an Info object using an already parsed JSON object. 255 * 256 * @param jsonObject the parsed JSON object. 257 */ 258 Info(JsonObject jsonObject) { 259 super(jsonObject); 260 } 261 262 /** 263 * Gets the item type. 264 * 265 * @return the item's type. 266 */ 267 public String getType() { 268 return this.type; 269 } 270 271 /** 272 * Gets a unique string identifying the version of the item. 273 * 274 * @return a unique string identifying the version of the item. 275 */ 276 public String getEtag() { 277 return this.etag; 278 } 279 280 /** 281 * Gets the name of the item. 282 * 283 * @return the name of the item. 284 */ 285 public String getName() { 286 return this.name; 287 } 288 289 /** 290 * Sets the name of the item. 291 * 292 * @param name the new name of the item. 293 */ 294 public void setName(String name) { 295 this.name = name; 296 this.addPendingChange("name", name); 297 } 298 299 /** 300 * Gets the time the item was created. 301 * 302 * @return the time the item was created. 303 */ 304 public Date getCreatedAt() { 305 return this.createdAt; 306 } 307 308 /** 309 * Gets the time the item was last modified. 310 * 311 * @return the time the item was last modified. 312 */ 313 public Date getModifiedAt() { 314 return this.modifiedAt; 315 } 316 317 /** 318 * Gets the description of the item. 319 * 320 * @return the description of the item. 321 */ 322 public String getDescription() { 323 return this.description; 324 } 325 326 /** 327 * Sets the description of the item. 328 * 329 * @param description the new description of the item. 330 */ 331 public void setDescription(String description) { 332 this.description = description; 333 this.addPendingChange("description", description); 334 } 335 336 /** 337 * Gets the size of the item in bytes. 338 * 339 * @return the size of the item in bytes. 340 */ 341 public long getSize() { 342 return this.size; 343 } 344 345 /** 346 * Gets the path of folders to the item, starting at the root. 347 * 348 * @return the path of folders to the item. 349 */ 350 public List<BoxFolder.Info> getPathCollection() { 351 return this.pathCollection; 352 } 353 354 /** 355 * Gets info about the user who created the item. 356 * 357 * @return info about the user who created the item. 358 */ 359 public BoxUser.Info getCreatedBy() { 360 return this.createdBy; 361 } 362 363 /** 364 * Gets info about the user who last modified the item. 365 * 366 * @return info about the user who last modified the item. 367 */ 368 public BoxUser.Info getModifiedBy() { 369 return this.modifiedBy; 370 } 371 372 /** 373 * Gets the time that the item was trashed. 374 * 375 * @return the time that the item was trashed. 376 */ 377 public Date getTrashedAt() { 378 return this.trashedAt; 379 } 380 381 /** 382 * Gets the time that the item was purged from the trash. 383 * 384 * @return the time that the item was purged from the trash. 385 */ 386 public Date getPurgedAt() { 387 return this.purgedAt; 388 } 389 390 /** 391 * Gets the time that the item was created according to the uploader. 392 * 393 * @return the time that the item was created according to the uploader. 394 */ 395 public Date getContentCreatedAt() { 396 return this.contentCreatedAt; 397 } 398 399 /** 400 * Gets the time that the item was last modified according to the uploader. 401 * 402 * @return the time that the item was last modified according to the uploader. 403 */ 404 public Date getContentModifiedAt() { 405 return this.contentModifiedAt; 406 } 407 408 /** 409 * Gets the expires at time for this item. 410 * 411 * @return the time that the item will expire at. 412 */ 413 public Date getExpiresAt() { 414 return this.expiresAt; 415 } 416 417 /** 418 * Gets info about the user who owns the item. 419 * 420 * @return info about the user who owns the item. 421 */ 422 public BoxUser.Info getOwnedBy() { 423 return this.ownedBy; 424 } 425 426 /** 427 * Gets the shared link for the item. 428 * 429 * @return the shared link for the item. 430 */ 431 public BoxSharedLink getSharedLink() { 432 return this.sharedLink; 433 } 434 435 /** 436 * Sets a shared link for the item. 437 * 438 * @param sharedLink the shared link for the item. 439 */ 440 public void setSharedLink(BoxSharedLink sharedLink) { 441 this.removeChildObject("shared_link"); 442 this.sharedLink = sharedLink; 443 this.addChildObject("shared_link", sharedLink); 444 } 445 446 /** 447 * Removes the shared link for the item. 448 */ 449 public void removeSharedLink() { 450 this.addChildObject("shared_link", null); 451 } 452 453 /** 454 * Gets a unique ID for use with the {@link EventStream}. 455 * 456 * @return a unique ID for use with the EventStream. 457 */ 458 public String getSequenceID() { 459 return this.sequenceID; 460 } 461 462 /** 463 * Gets a list of all the tags applied to the item. 464 * 465 * <p>Note that this field isn't populated by default and must be specified as a field parameter when getting 466 * Info about the item.</p> 467 * 468 * @return a list of all the tags applied to the item. 469 */ 470 public List<String> getTags() { 471 return this.tags; 472 } 473 474 /** 475 * Sets the tags for an item. 476 * 477 * @param tags The new tags for the item. 478 */ 479 public void setTags(List<String> tags) { 480 this.tags = tags; 481 JsonArray tagsJSON = new JsonArray(); 482 for (String tag : tags) { 483 tagsJSON.add(tag); 484 } 485 this.addPendingChange("tags", tagsJSON); 486 } 487 488 /** 489 * Gets info about the parent folder of the item. 490 * 491 * @return info about the parent folder of the item. 492 */ 493 public BoxFolder.Info getParent() { 494 return this.parent; 495 } 496 497 /** 498 * Gets the status of the item. 499 * 500 * @return the status of the item. 501 */ 502 public String getItemStatus() { 503 return this.itemStatus; 504 } 505 506 /** 507 * Gets info about the collections that this item belongs to. 508 * 509 * @return info about the collections that this item belongs to. 510 */ 511 public Iterable<BoxCollection.Info> getCollections() { 512 return this.collections; 513 } 514 515 /** 516 * Sets the collections that this item belongs to. 517 * 518 * @param collections the new list of collections that this item should belong to. 519 */ 520 public void setCollections(Iterable<BoxCollection> collections) { 521 if (this.collections == null) { 522 this.collections = new HashSet<BoxCollection.Info>(); 523 } else { 524 this.collections.clear(); 525 } 526 527 JsonArray jsonArray = new JsonArray(); 528 for (BoxCollection collection : collections) { 529 JsonObject jsonObject = new JsonObject(); 530 jsonObject.add("id", collection.getID()); 531 jsonArray.add(jsonObject); 532 this.collections.add(collection.new Info()); 533 } 534 this.addPendingChange("collections", jsonArray); 535 } 536 537 @Override 538 protected void parseJSONMember(JsonObject.Member member) { 539 super.parseJSONMember(member); 540 JsonValue value = member.getValue(); 541 String memberName = member.getName(); 542 543 try { 544 if (memberName.equals("sequence_id")) { 545 this.sequenceID = value.asString(); 546 } else if (memberName.equals("type")) { 547 this.type = value.asString(); 548 } else if (memberName.equals("etag")) { 549 this.etag = value.asString(); 550 } else if (memberName.equals("name")) { 551 this.name = value.asString(); 552 } else if (memberName.equals("created_at")) { 553 this.createdAt = BoxDateFormat.parse(value.asString()); 554 } else if (memberName.equals("modified_at")) { 555 this.modifiedAt = BoxDateFormat.parse(value.asString()); 556 } else if (memberName.equals("description")) { 557 this.description = value.asString(); 558 } else if (memberName.equals("size")) { 559 this.size = Double.valueOf(value.toString()).longValue(); 560 } else if (memberName.equals("trashed_at")) { 561 this.trashedAt = BoxDateFormat.parse(value.asString()); 562 } else if (memberName.equals("purged_at")) { 563 this.purgedAt = BoxDateFormat.parse(value.asString()); 564 } else if (memberName.equals("content_created_at")) { 565 this.contentCreatedAt = BoxDateFormat.parse(value.asString()); 566 } else if (memberName.equals("content_modified_at")) { 567 this.contentModifiedAt = BoxDateFormat.parse(value.asString()); 568 } else if (memberName.equals("expires_at")) { 569 this.expiresAt = BoxDateFormat.parse(value.asString()); 570 } else if (memberName.equals("path_collection")) { 571 this.pathCollection = this.parsePathCollection(value.asObject()); 572 } else if (memberName.equals("created_by")) { 573 this.createdBy = this.parseUserInfo(value.asObject()); 574 } else if (memberName.equals("modified_by")) { 575 this.modifiedBy = this.parseUserInfo(value.asObject()); 576 } else if (memberName.equals("owned_by")) { 577 this.ownedBy = this.parseUserInfo(value.asObject()); 578 } else if (memberName.equals("shared_link")) { 579 if (this.sharedLink == null) { 580 this.setSharedLink(new BoxSharedLink(value.asObject())); 581 } else { 582 this.sharedLink.update(value.asObject()); 583 } 584 } else if (memberName.equals("tags")) { 585 this.tags = this.parseTags(value.asArray()); 586 } else if (memberName.equals("parent")) { 587 JsonObject jsonObject = value.asObject(); 588 if (this.parent == null) { 589 String id = jsonObject.get("id").asString(); 590 BoxFolder parentFolder = new BoxFolder(getAPI(), id); 591 this.parent = parentFolder.new Info(jsonObject); 592 } else { 593 this.parent.update(jsonObject); 594 } 595 } else if (memberName.equals("item_status")) { 596 this.itemStatus = value.asString(); 597 } else if (memberName.equals("collections")) { 598 if (this.collections == null) { 599 this.collections = new HashSet<BoxCollection.Info>(); 600 } else { 601 this.collections.clear(); 602 } 603 604 BoxAPIConnection api = getAPI(); 605 JsonArray jsonArray = value.asArray(); 606 for (JsonValue arrayValue : jsonArray) { 607 JsonObject jsonObject = arrayValue.asObject(); 608 String id = jsonObject.get("id").asString(); 609 BoxCollection collection = new BoxCollection(api, id); 610 BoxCollection.Info collectionInfo = collection.new Info(jsonObject); 611 this.collections.add(collectionInfo); 612 } 613 } 614 } catch (Exception e) { 615 throw new BoxDeserializationException(memberName, value.toString(), e); 616 } 617 } 618 619 private List<BoxFolder.Info> parsePathCollection(JsonObject jsonObject) { 620 int count = jsonObject.get("total_count").asInt(); 621 List<BoxFolder.Info> pathCollection = new ArrayList<BoxFolder.Info>(count); 622 JsonArray entries = jsonObject.get("entries").asArray(); 623 for (JsonValue value : entries) { 624 JsonObject entry = value.asObject(); 625 String id = entry.get("id").asString(); 626 BoxFolder folder = new BoxFolder(getAPI(), id); 627 pathCollection.add(folder.new Info(entry)); 628 } 629 630 return pathCollection; 631 } 632 633 private BoxUser.Info parseUserInfo(JsonObject jsonObject) { 634 String userID = jsonObject.get("id").asString(); 635 BoxUser user = new BoxUser(getAPI(), userID); 636 return user.new Info(jsonObject); 637 } 638 639 private List<String> parseTags(JsonArray jsonArray) { 640 List<String> tags = new ArrayList<String>(jsonArray.size()); 641 for (JsonValue value : jsonArray) { 642 tags.add(value.asString()); 643 } 644 645 return tags; 646 } 647 } 648}