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.Iterator;
009
010/**
011 * Collections contain information about the items contained inside of them, including files and
012 * folders. The only collection available currently is a “Favorites” collection.
013 *
014 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link
015 * BoxAPIException} (unchecked meaning that the compiler won't force you to handle it) if an error
016 * occurs. If you wish to implement custom error handling for errors related to the Box REST API,
017 * you should capture this exception explicitly.
018 */
019@BoxResourceType("collection")
020public class BoxCollection extends BoxResource implements Iterable<BoxItem.Info> {
021
022  /** Get Collections URL Template. */
023  public static final URLTemplate GET_COLLECTIONS_URL_TEMPLATE = new URLTemplate("collections/");
024  /** Get Collection Items URL Template. */
025  public static final URLTemplate GET_COLLECTION_ITEMS_URL =
026      new URLTemplate("collections/%s/items/");
027
028  /**
029   * Constructs a BoxCollection for a collection with a given ID.
030   *
031   * @param api the API connection to be used by the collection.
032   * @param id the ID of the collection.
033   */
034  public BoxCollection(BoxAPIConnection api, String id) {
035    super(api, id);
036  }
037
038  /**
039   * Gets an iterable of all the collections for the given user.
040   *
041   * @param api the API connection to be used when retrieving the collections.
042   * @return an iterable containing info about all the collections.
043   */
044  public static Iterable<BoxCollection.Info> getAllCollections(final BoxAPIConnection api) {
045    return () -> {
046      URL url = GET_COLLECTIONS_URL_TEMPLATE.build(api.getBaseURL());
047      return new BoxCollectionIterator(api, url);
048    };
049  }
050
051  /**
052   * Returns an iterable containing the items in this collection. Iterating over the iterable
053   * returned by this method is equivalent to iterating over this BoxCollection directly.
054   *
055   * @return an iterable containing the items in this collection.
056   */
057  public Iterable<BoxItem.Info> getItems() {
058    return this;
059  }
060
061  /**
062   * Returns an iterable containing the items in this collection and specifies which attributes to
063   * include in the response.
064   *
065   * @param fields the fields to retrieve.
066   * @return an iterable containing the items in this collection.
067   */
068  public Iterable<BoxItem.Info> getItems(final String... fields) {
069    return () -> {
070      String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
071      URL url =
072          GET_COLLECTION_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), queryString, getID());
073      return new BoxItemIterator(getAPI(), url);
074    };
075  }
076
077  /**
078   * Retrieves a specific range of items in this collection.
079   *
080   * @param offset the index of the first item to retrieve.
081   * @param limit the maximum number of items to retrieve after the offset.
082   * @param fields the fields to retrieve.
083   * @return a partial collection containing the specified range of items.
084   */
085  public PartialCollection<BoxItem.Info> getItemsRange(long offset, long limit, String... fields) {
086    QueryStringBuilder builder =
087        new QueryStringBuilder().appendParam("offset", offset).appendParam("limit", limit);
088
089    if (fields.length > 0) {
090      builder.appendParam("fields", fields);
091    }
092
093    URL url =
094        GET_COLLECTION_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), builder.toString(), getID());
095    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
096    try (BoxJSONResponse response = request.send()) {
097      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
098
099      String totalCountString = responseJSON.get("total_count").toString();
100      long fullSize = Double.valueOf(totalCountString).longValue();
101      PartialCollection<BoxItem.Info> items = new PartialCollection<>(offset, limit, fullSize);
102      JsonArray entries = responseJSON.get("entries").asArray();
103      for (JsonValue entry : entries) {
104        BoxItem.Info entryInfo =
105            (BoxItem.Info) BoxResource.parseInfo(this.getAPI(), entry.asObject());
106        if (entryInfo != null) {
107          items.add(entryInfo);
108        }
109      }
110      return items;
111    }
112  }
113
114  /**
115   * Returns an iterator over the items in this collection.
116   *
117   * @return an iterator over the items in this collection.
118   */
119  @Override
120  public Iterator<BoxItem.Info> iterator() {
121    URL url =
122        GET_COLLECTION_ITEMS_URL.build(this.getAPI().getBaseURL(), BoxCollection.this.getID());
123    return new BoxItemIterator(BoxCollection.this.getAPI(), url);
124  }
125
126  /** Contains information about a BoxCollection. */
127  public class Info extends BoxResource.Info {
128    private String collectionType;
129    private String name;
130
131    /** Constructs an empty Info object. */
132    public Info() {
133      super();
134    }
135
136    /**
137     * Constructs an Info object by parsing information from a JSON string.
138     *
139     * @param json the JSON string to parse.
140     */
141    public Info(String json) {
142      super(json);
143    }
144
145    /**
146     * Constructs an Info object using an already parsed JSON object.
147     *
148     * @param jsonObject the parsed JSON object.
149     */
150    Info(JsonObject jsonObject) {
151      super(jsonObject);
152    }
153
154    /**
155     * Gets the type of the collection.
156     *
157     * @return the type of the collection.
158     */
159    public String getCollectionType() {
160      return this.collectionType;
161    }
162
163    /**
164     * Gets the name of the collection.
165     *
166     * @return the name of the collection.
167     */
168    public String getName() {
169      return this.name;
170    }
171
172    @Override
173    public BoxCollection getResource() {
174      return BoxCollection.this;
175    }
176
177    @Override
178    protected void parseJSONMember(JsonObject.Member member) {
179      super.parseJSONMember(member);
180
181      String memberName = member.getName();
182      JsonValue value = member.getValue();
183      if (memberName.equals("collection_type")) {
184        this.collectionType = value.asString();
185      } else if (memberName.equals("name")) {
186        this.name = value.asString();
187      }
188    }
189  }
190}