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}