com.box.sdk.BoxResourceIterable Maven / Gradle / Ivy
package com.box.sdk;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.NoSuchElementException;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
/**
* Common implementation for paging support.
*
* @param
* type of iterated entity
*/
public abstract class BoxResourceIterable implements Iterable {
/**
* Parameter for max page size.
*/
public static final String PARAMETER_LIMIT = "limit";
/**
* Parameter for marker for the beginning of next page.
*/
public static final String PARAMETER_MARKER = "marker";
/**
* Body Parameter for marker for the beginning of next page.
*/
public static final String BODY_PARAMETER_MARKER_NEXT = "next_marker";
/**
* Body parameter for page entries.
*/
public static final String BODY_PARAMETER_ENTRIES = "entries";
/**
* The API connection to be used by the resource.
*/
private final BoxAPIConnection api;
/**
* To end-point with paging support.
*/
private final URL url;
/**
* The maximum number of items to return in a page.
*/
private final int limit;
/**
* Constructor.
*
* @param api
* the API connection to be used by the resource
* @param url
* to end-point with paging support
* @param limit
* the maximum number of items to return in a page
*/
public BoxResourceIterable(BoxAPIConnection api, URL url, int limit) {
this.api = api;
this.url = url;
this.limit = limit;
}
/**
* Factory to build a new instance for a received JSON item.
*
* @param jsonObject
* of the item
* @return the item instance
*/
protected abstract T factory(JsonObject jsonObject);
/**
* Builds internal read-only iterator over {@link BoxResource}-s.
*
* @return iterator implementation
* @see Iterable#iterator()
*/
@Override
public Iterator iterator() {
return new IteratorImpl();
}
/**
* Paging implementation.
*/
private class IteratorImpl implements Iterator {
/**
* Base 64 encoded string that represents where the paging should being. It should be left blank to begin
* paging.
*/
private String markerNext;
/**
* Current loaded page.
*/
private JsonArray page;
/**
* Cursor within the page (index of a next item for read).
*/
private int pageCursor;
/**
* Constructor.
*/
IteratorImpl() {
this.loadNextPage();
}
/**
* Loads next page.
*/
private void loadNextPage() {
String existingQuery = BoxResourceIterable.this.url.getQuery();
QueryStringBuilder builder = new QueryStringBuilder(existingQuery);
builder.appendParam(PARAMETER_LIMIT, BoxResourceIterable.this.limit);
if (this.markerNext != null) {
builder.appendParam(PARAMETER_MARKER, this.markerNext);
}
URL url;
try {
url = builder.addToURL(BoxResourceIterable.this.url);
} catch (MalformedURLException e) {
throw new BoxAPIException("Couldn't append a query string to the provided URL.");
}
BoxAPIRequest request = new BoxAPIRequest(BoxResourceIterable.this.api, url, "GET");
BoxJSONResponse response = (BoxJSONResponse) request.send();
JsonObject pageBody = JsonObject.readFrom(response.getJSON());
JsonValue markerNextValue = pageBody.get(BODY_PARAMETER_MARKER_NEXT);
if (markerNextValue != null && markerNextValue.isString()) {
this.markerNext = markerNextValue.asString();
} else {
this.markerNext = null;
}
this.page = pageBody.get(BODY_PARAMETER_ENTRIES).asArray();
this.pageCursor = 0;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
if (this.pageCursor < this.page.size()) {
return true;
}
if (this.markerNext == null || this.markerNext.isEmpty()) {
return false;
}
this.loadNextPage();
return !this.page.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
public T next() {
if (!this.hasNext()) {
throw new NoSuchElementException();
}
JsonObject entry = this.page.get(this.pageCursor++).asObject();
return BoxResourceIterable.this.factory(entry);
}
/**
* @throws UnsupportedOperationException
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}