001package com.plivo.api.models.base;
002
003import com.fasterxml.jackson.databind.annotation.JsonSerialize;
004import com.fasterxml.jackson.databind.annotation.JsonSerialize.Typing;
005import com.plivo.api.PlivoClient;
006import com.plivo.api.exceptions.IterableError;
007import com.plivo.api.exceptions.PlivoRestException;
008import com.plivo.api.util.Utils;
009import java.io.IOException;
010import java.util.Deque;
011import java.util.Iterator;
012import java.util.Map;
013import java.util.concurrent.ConcurrentLinkedDeque;
014import retrofit2.Call;
015import retrofit2.Response;
016
017/**
018 * Lists instances of a resource, possibly filtered.
019 *
020 * @param <T> The type of the resource.
021 */
022@JsonSerialize(typing = Typing.STATIC)
023public abstract class Lister<T extends BaseResource> extends BaseRequest<T> implements Iterable<T> {
024
025  protected Integer limit = null;
026  protected Integer offset = null;
027
028  @Override
029  public Lister<T> client(final PlivoClient plivoClient) {
030    this.plivoClient = plivoClient;
031    return this;
032  }
033
034
035  /**
036   * @return Used to display the number of results per page. The maximum number of results that can
037   * be fetched is 20.
038   */
039  public Integer limit() {
040    return this.limit;
041  }
042
043  /**
044   * @return Denotes the number of value items by which the results should be offset.
045   */
046  public Integer offset() {
047    return this.offset;
048  }
049
050  /**
051   * @param limit Used to display the number of results per page. The maximum number of results that
052   * can be fetched is 20.
053   */
054  public Lister<T> limit(final Integer limit) {
055    this.limit = limit;
056    return this;
057  }
058
059  /**
060   * @param offset Denotes the number of value items by which the results should be offset.
061   */
062  public Lister<T> offset(final Integer offset) {
063    this.offset = offset;
064    return this;
065  }
066
067  protected abstract Call<ListResponse<T>> obtainCall();
068
069  /**
070   * Actually list instances of the resource.
071   */
072  public ListResponse<T> list() throws IOException, PlivoRestException {
073    validate();
074    Response<ListResponse<T>> response = obtainCall().execute();
075
076    handleResponse(response);
077
078    return response.body();
079  }
080
081  protected Map<String, Object> toMap() {
082    client();
083    return Utils.objectToMap(plivoClient.getObjectMapper(), this);
084  }
085
086  @Override
087  public Iterator<T> iterator() throws IterableError {
088    if (limit == null) {
089      limit = 20;
090    }
091
092    if (offset == null) {
093      offset = 0;
094    }
095
096    return new Iterator<T>() {
097      Deque<T> items = new ConcurrentLinkedDeque<>();
098
099      @Override
100      public boolean hasNext() {
101        if (!items.isEmpty()) {
102          return true;
103        }
104
105        try {
106          ListResponse<T> itemList = Lister.this.list();
107          if (itemList.getObjects().isEmpty()) {
108            return false;
109          }
110          this.items.addAll(itemList.getObjects());
111          offset += limit;
112        } catch (IOException | PlivoRestException exception) {
113          throw new IterableError();
114        }
115        return true;
116      }
117
118      @Override
119      public T next() {
120        if (items.isEmpty()) {
121          try {
122            ListResponse<T> itemList = Lister.this.list();
123            this.items.addAll(itemList.getObjects());
124            offset += limit;
125          } catch (IOException | PlivoRestException exception) {
126            throw new IterableError();
127          }
128        }
129
130        return items.removeFirst();
131      }
132    };
133  }
134}