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