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.PlivoValidationException; 007import com.plivo.api.exceptions.IterableError; 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 Lister<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 Lister<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 Lister<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 Lister<T> offset(final Integer offset) { 066 this.offset = offset; 067 return this; 068 } 069 070 protected abstract Call<ListResponse<T>> obtainCall() throws PlivoValidationException; 071 072 /** 073 * Actually list instances of the resource. 074 */ 075 public ListResponse<T> list() throws IOException, PlivoRestException, PlivoValidationException { 076 validate(); 077 Response<ListResponse<T>> response = obtainCall().execute(); 078 079 handleResponse(response); 080 081 return response.body(); 082 } 083 084 public Long get() throws IOException, PlivoRestException, PlivoValidationException { 085 validate(); 086 Response<ListResponse<T>> response = obtainCall().execute(); 087 handleResponse(response); 088 try { 089 return response.body().getMeta().getTotalCount(); 090 } catch (Exception e) { 091 return 0L; 092 } 093 } 094 095 096 protected Map<String, Object> toMap() { 097 client(); 098 return Utils.objectToMap(plivoClient.getObjectMapper(), this); 099 } 100 101 @Override 102 public Iterator<T> iterator() throws IterableError { 103 if (limit == null) { 104 limit = 20; 105 } 106 107 if (offset == null) { 108 offset = 0; 109 } 110 111 return new Iterator<T>() { 112 Deque<T> items = new ConcurrentLinkedDeque<>(); 113 114 @Override 115 public boolean hasNext() { 116 if (!items.isEmpty()) { 117 return true; 118 } 119 120 try { 121 ListResponse<T> itemList = Lister.this.list(); 122 if (itemList.getObjects().isEmpty()) { 123 return false; 124 } 125 this.items.addAll(itemList.getObjects()); 126 offset += limit; 127 } catch (IOException | PlivoRestException | PlivoValidationException exception) { 128 throw new IterableError(); 129 } 130 return true; 131 } 132 133 @Override 134 public T next() { 135 if (items.isEmpty()) { 136 try { 137 ListResponse<T> itemList = Lister.this.list(); 138 this.items.addAll(itemList.getObjects()); 139 offset += limit; 140 } catch (IOException | PlivoRestException | PlivoValidationException exception) { 141 throw new IterableError(); 142 } 143 } 144 145 return items.removeFirst(); 146 } 147 }; 148 } 149}