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.PlivoValidationException;
008import com.plivo.api.exceptions.PlivoRestException;
009import com.plivo.api.util.Utils;
010
011import java.io.IOException;
012import java.util.Deque;
013import java.util.Iterator;
014import java.util.Map;
015import java.util.concurrent.ConcurrentLinkedDeque;
016
017import retrofit2.Call;
018import retrofit2.Response;
019
020/**
021 * Lists instances of a resource, possibly filtered.
022 *
023 * @param <T> The type of the resource.
024 */
025@JsonSerialize(typing = Typing.STATIC)
026public abstract class VoiceLister<T extends BaseResource> extends BaseRequest<T> implements Iterable<T> {
027
028  protected Integer limit = null;
029  protected Integer offset = null;
030
031  @Override
032  public VoiceLister<T> client(final PlivoClient plivoClient) {
033    this.plivoClient = plivoClient;
034    return this;
035  }
036
037
038  /**
039   * @return Used to display the number of results per page. The maximum number of results that can
040   * be fetched is 20.
041   */
042  public Integer limit() {
043    return this.limit;
044  }
045
046  /**
047   * @return Denotes the number of value items by which the results should be offset.
048   */
049  public Integer offset() {
050    return this.offset;
051  }
052
053  /**
054   * @param limit Used to display the number of results per page. The maximum number of results that
055   *              can be fetched is 20.
056   */
057  public VoiceLister<T> limit(final Integer limit) {
058    this.limit = limit;
059    return this;
060  }
061
062  /**
063   * @param offset Denotes the number of value items by which the results should be offset.
064   */
065  public VoiceLister<T> offset(final Integer offset) {
066    this.offset = offset;
067    return this;
068  }
069
070  protected abstract Call<ListResponse<T>> obtainCall() throws PlivoValidationException;
071  protected abstract Call<ListResponse<T>> obtainFallback1Call() throws PlivoValidationException;
072  protected abstract Call<ListResponse<T>> obtainFallback2Call() throws PlivoValidationException;
073
074  /**
075   * Actually list instances of the resource.
076   */
077  public ListResponse<T> list() throws IOException, PlivoRestException, PlivoValidationException {
078    validate();
079    Response<ListResponse<T>> response = obtainCall().execute();
080
081    if(response.code()>=500){
082      response = obtainFallback1Call().execute();
083      if(response.code()>=500){
084        response = obtainFallback2Call().execute();
085      }
086    }
087
088    handleResponse(response);
089
090    return response.body();
091  }
092
093  public Long get() throws IOException, PlivoRestException, PlivoValidationException {
094    validate();
095    Response<ListResponse<T>> response = obtainCall().execute();
096
097    if(response.code()>=500){
098      response = obtainFallback1Call().execute();
099      if(response.code()>=500){
100        response = obtainFallback2Call().execute();
101      }
102    }
103
104    handleResponse(response);
105    try {
106      return response.body().getMeta().getTotalCount();
107    } catch (Exception e) {
108      return 0L;
109    }
110  }
111
112
113  protected Map<String, Object> toMap() {
114    client();
115    return Utils.objectToMap(plivoClient.getObjectMapper(), this);
116  }
117
118  @Override
119  public Iterator<T> iterator() throws IterableError {
120    if (limit == null) {
121      limit = 20;
122    }
123
124    if (offset == null) {
125      offset = 0;
126    }
127
128    return new Iterator<T>() {
129      Deque<T> items = new ConcurrentLinkedDeque<>();
130
131      @Override
132      public boolean hasNext() {
133        if (!items.isEmpty()) {
134          return true;
135        }
136
137        try {
138          ListResponse<T> itemList = VoiceLister.this.list();
139          if (itemList.getObjects().isEmpty()) {
140            return false;
141          }
142          this.items.addAll(itemList.getObjects());
143          offset += limit;
144        } catch (IOException | PlivoRestException | PlivoValidationException exception) {
145          throw new IterableError();
146        }
147        return true;
148      }
149
150      @Override
151      public T next() {
152        if (items.isEmpty()) {
153          try {
154            ListResponse<T> itemList = VoiceLister.this.list();
155            this.items.addAll(itemList.getObjects());
156            offset += limit;
157          } catch (IOException | PlivoRestException | PlivoValidationException exception) {
158            throw new IterableError();
159          }
160        }
161
162        return items.removeFirst();
163      }
164    };
165  }
166}