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