001package com.plivo.api; 002 003import com.fasterxml.jackson.core.JsonGenerator; 004import com.fasterxml.jackson.core.JsonParser; 005import com.fasterxml.jackson.core.JsonProcessingException; 006import com.fasterxml.jackson.databind.BeanDescription; 007import com.fasterxml.jackson.databind.DeserializationConfig; 008import com.fasterxml.jackson.databind.DeserializationContext; 009import com.fasterxml.jackson.databind.DeserializationFeature; 010import com.fasterxml.jackson.databind.JavaType; 011import com.fasterxml.jackson.databind.JsonDeserializer; 012import com.fasterxml.jackson.databind.ObjectMapper; 013import com.fasterxml.jackson.databind.PropertyNamingStrategy; 014import com.fasterxml.jackson.databind.SerializationFeature; 015import com.fasterxml.jackson.databind.SerializerProvider; 016import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; 017import com.fasterxml.jackson.databind.module.SimpleModule; 018import com.fasterxml.jackson.databind.ser.std.StdSerializer; 019import com.plivo.api.util.Utils; 020import okhttp3.Credentials; 021import okhttp3.Interceptor; 022import okhttp3.OkHttpClient; 023import okhttp3.Protocol; 024import okhttp3.Response; 025import okhttp3.ResponseBody; 026import okhttp3.logging.HttpLoggingInterceptor; 027import okhttp3.logging.HttpLoggingInterceptor.Level; 028import retrofit2.Retrofit; 029import retrofit2.converter.jackson.JacksonConverterFactory; 030 031import java.io.BufferedReader; 032import java.io.IOException; 033import java.io.InputStream; 034import java.io.InputStreamReader; 035import java.net.ProtocolException; 036import java.text.SimpleDateFormat; 037 038public class PlivoClient { 039 040 private static SimpleModule simpleModule = new SimpleModule(); 041 protected static String BASE_URL = "https://api.plivo.com/v1/"; 042 private static String version = "Unknown Version"; 043 private boolean testing = false; 044 private static ObjectMapper objectMapper = new ObjectMapper(); 045 046 public void setTesting(boolean testing) { 047 this.testing = testing; 048 } 049 050 public boolean isTesting() { 051 return testing; 052 } 053 054 static { 055 simpleModule.setDeserializerModifier(new BeanDeserializerModifier() { 056 @Override 057 public JsonDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type, 058 BeanDescription beanDesc, JsonDeserializer<?> deserializer) { 059 return new JsonDeserializer<Enum>() { 060 @Override 061 public Enum deserialize(JsonParser jp, DeserializationContext ctxt) 062 throws IOException, JsonProcessingException { 063 Class<? extends Enum> rawClass = (Class<Enum<?>>) type.getRawClass(); 064 return Enum.valueOf(rawClass, jp.getValueAsString().toUpperCase().replace("-", "_")); 065 } 066 }; 067 } 068 }); 069 simpleModule.addSerializer(Enum.class, new StdSerializer<Enum>(Enum.class) { 070 @Override 071 public void serialize(Enum value, JsonGenerator gen, SerializerProvider provider) 072 throws IOException { 073 gen.writeString(value.name().toLowerCase().replace("_", "-")); 074 } 075 }); 076 } 077 078 { 079 try { 080 InputStream inputStream = PlivoClient.class 081 .getResource("version.txt") 082 .openStream(); 083 084 version = new BufferedReader(new InputStreamReader(inputStream)).readLine(); 085 } catch (IOException ignored) { 086 ignored.printStackTrace(); 087 } 088 objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 089 objectMapper.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS); 090 objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); 091 objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); 092 } 093 094 private final Interceptor interceptor = new HttpLoggingInterceptor() 095 .setLevel(Level.BODY); 096 private final String authId; 097 private final String authToken; 098 private OkHttpClient httpClient; 099 private Retrofit retrofit; 100 private PlivoAPIService apiService = null; 101 102 /** 103 * Constructs a new PlivoClient instance. To set a proxy, timeout etc, you can pass in an OkHttpClient.Builder, on which you can set 104 * the timeout and proxy using: 105 * 106 * <pre><code> 107 * new OkHttpClient.Builder() 108 * .proxy(proxy) 109 * .connectTimeout(1, TimeUnit.MINUTES); 110 * </code></pre> 111 * 112 * @param authId 113 * @param authToken 114 * @param httpClientBuilder 115 * @param baseUrl 116 * @param simpleModule 117 */ 118 public PlivoClient(String authId, String authToken, OkHttpClient.Builder httpClientBuilder, final String baseUrl, final SimpleModule simpleModule) { 119 if (!(Utils.isAccountIdValid(authId) || Utils.isSubaccountIdValid(authId))) { 120 throw new IllegalArgumentException("invalid account ID"); 121 } 122 123 this.authId = authId; 124 this.authToken = authToken; 125 this.objectMapper.registerModule(simpleModule); 126 127 httpClient = httpClientBuilder 128 .addNetworkInterceptor(interceptor) 129 .addInterceptor(chain -> chain.proceed( 130 chain.request() 131 .newBuilder() 132 .addHeader("Authorization", Credentials.basic(getAuthId(), getAuthToken())) 133 .addHeader("User-Agent", String.format("%s/%s (Implementation: %s %s %s, Specification: %s %s %s)", "plivo-java", version, 134 Runtime.class.getPackage().getImplementationVendor(), 135 Runtime.class.getPackage().getImplementationTitle(), 136 Runtime.class.getPackage().getImplementationVersion(), 137 Runtime.class.getPackage().getSpecificationVendor(), 138 Runtime.class.getPackage().getSpecificationTitle(), 139 Runtime.class.getPackage().getSpecificationVersion() 140 )) 141 .build() 142 )) 143 .addNetworkInterceptor(chain -> { 144 Response response; 145 try { 146 response = chain.proceed(chain.request()); 147 } catch (ProtocolException protocolException) { 148 // We return bodies for HTTP 204! 149 response = new Response.Builder() 150 .request(chain.request()) 151 .code(204) 152 .protocol(Protocol.HTTP_1_1) 153 .body(ResponseBody.create(null, new byte[]{})) 154 .build(); 155 } 156 return response; 157 }).build(); 158 159 retrofit = new Retrofit.Builder() 160 .client(httpClient) 161 .baseUrl(baseUrl) 162 .addConverterFactory(JacksonConverterFactory.create(objectMapper)) 163 .build(); 164 165 this.apiService = retrofit.create(PlivoAPIService.class); 166 } 167 168 /** 169 * Constructs a new PlivoClient instance. To set a proxy, timeout etc, you can pass in an OkHttpClient.Builder, on which you can set 170 * the timeout and proxy using: 171 * 172 * <pre><code> 173 * new OkHttpClient.Builder() 174 * .proxy(proxy) 175 * .connectTimeout(1, TimeUnit.MINUTES); 176 * </code></pre> 177 * 178 * @param authId 179 * @param authToken 180 */ 181 public PlivoClient(String authId, String authToken) { 182 this(authId, authToken, new OkHttpClient.Builder(), BASE_URL, simpleModule); 183 } 184 185 /** 186 * Constructs a new PlivoClient instance. To set a proxy, timeout etc, you can pass in an OkHttpClient.Builder, on which you can set 187 * the timeout and proxy using: 188 * 189 * <pre><code> 190 * new OkHttpClient.Builder() 191 * .proxy(proxy) 192 * .connectTimeout(1, TimeUnit.MINUTES); 193 * </code></pre> 194 * 195 * @param authId 196 * @param authToken 197 * @param httpClientBuilder 198 */ 199 public PlivoClient(String authId, String authToken, OkHttpClient.Builder httpClientBuilder) { 200 this(authId, authToken, httpClientBuilder, BASE_URL, simpleModule); 201 } 202 203 public static ObjectMapper getObjectMapper() { 204 return objectMapper; 205 } 206 207 Retrofit getRetrofit() { 208 return retrofit; 209 } 210 211 public PlivoAPIService getApiService() { 212 return apiService; 213 } 214 215 void setApiService(PlivoAPIService apiService) { 216 this.apiService = apiService; 217 } 218 219 public String getAuthId() { 220 return authId; 221 } 222 223 public String getAuthToken() { 224 return authToken; 225 } 226}