Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for 21.3.2 #103

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name := """avatax-rest-v2-api-java"""

organization := "net.avalara.avatax"

version := "21.3.1"
version := "21.6.0"

scalaVersion := "2.11.12"

Expand Down
752 changes: 701 additions & 51 deletions src/main/java/net/avalara/avatax/rest/client/AvaTaxClient.java

Large diffs are not rendered by default.

147 changes: 81 additions & 66 deletions src/main/java/net/avalara/avatax/rest/client/RestCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import net.avalara.avatax.rest.client.enums.ErrorCodeId;
import net.avalara.avatax.rest.client.enums.ErrorTargetCode;
import net.avalara.avatax.rest.client.models.ErrorDetail;
import net.avalara.avatax.rest.client.models.ErrorInfo;
import net.avalara.avatax.rest.client.models.ErrorResult;
import net.avalara.avatax.rest.client.models.*;
import net.avalara.avatax.rest.client.serializer.JsonSerializer;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
Expand All @@ -19,6 +19,8 @@
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.util.EntityUtils;

import java.util.concurrent.TimeUnit;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Callable;
Expand All @@ -31,8 +33,9 @@ public class RestCall<T> implements Callable<T> {
private String machineName;
private Object model;
private TypeToken<T> typeToken;
private UserConfiguration userConfiguration;

private RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, CloseableHttpClient client) {
private RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, CloseableHttpClient client, UserConfiguration userConfiguration) {
this.client = client;
this.appName = appName;
this.appVersion = appVersion;
Expand All @@ -42,121 +45,134 @@ private RestCall(String appName, String appVersion, String machineName, String e

if (method == "post") {
this.request = new HttpPost(environmentUrl + path.toString());
((HttpPost)this.request).setEntity(new StringEntity(JsonSerializer.SerializeObject(model), ContentType.create("application/json", "UTF-8")));
((HttpPost) this.request).setEntity(new StringEntity(JsonSerializer.SerializeObject(model), ContentType.create("application/json", "UTF-8")));
} else if (method == "get") {
this.request = new HttpGet(environmentUrl + path.toString());
} else if (method == "delete") {
this.request = new HttpDelete(environmentUrl + path.toString());
} else if (method == "put") {
this.request = new HttpPut(environmentUrl + path.toString());
((HttpPut)this.request).setEntity(new StringEntity(JsonSerializer.SerializeObject(model), ContentType.create("application/json", "UTF-8")));
((HttpPut) this.request).setEntity(new StringEntity(JsonSerializer.SerializeObject(model), ContentType.create("application/json", "UTF-8")));
}
if (userConfiguration == null) {
this.userConfiguration = new UserConfiguration();
} else {
this.userConfiguration = userConfiguration;
}

buildRequest(this.request);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, HttpClients.createDefault());
public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, HttpClients.createDefault(), userConfiguration);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, HttpClientBuilder httpClientBuilder) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder.build());
public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, HttpClientBuilder httpClientBuilder, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder.build(), userConfiguration);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken);

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, userConfiguration);
this.request.setHeader("Authorization", "Basic " + header);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, HttpClientBuilder httpClientBuilder) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder);

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, HttpClientBuilder httpClientBuilder, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder, userConfiguration);
this.request.setHeader("Authorization", "Basic " + header);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, String proxyHost, int proxyPort, String proxySchema) {
public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, String proxyHost, int proxyPort, String proxySchema, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, HttpClients.custom()
.setRoutePlanner(new DefaultProxyRoutePlanner(new HttpHost(proxyHost, proxyPort, proxySchema)))
.build());
.build(), userConfiguration);
}

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, String proxyHost, int proxyPort, String proxySchema) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, proxyHost, proxyPort, proxySchema);

public RestCall(String appName, String appVersion, String machineName, String environmentUrl, String header, String method, AvaTaxPath path, Object model, TypeToken<T> typeToken, String proxyHost, int proxyPort, String proxySchema, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, proxyHost, proxyPort, proxySchema, userConfiguration);
this.request.setHeader("Authorization", "Basic " + header);
}


@Override
public T call() throws Exception {

CloseableHttpResponse response = this.client.execute(this.request);
CloseableHttpResponse response;
T obj = null;
String json = null;
try {
HttpEntity entity = response.getEntity();
json = EntityUtils.toString(entity);
if (response.getStatusLine().getStatusCode() != 200 && response.getStatusLine().getStatusCode() != 201) {
throw new AvaTaxClientException((ErrorResult) JsonSerializer.DeserializeObject(json, ErrorResult.class), model);
}

if(ContentType.getOrDefault(entity).getMimeType().equals("application/json")) {
obj = (T)JsonSerializer.DeserializeObject(json, typeToken.getType());
}
else {
obj = (T)json;
int retryAttempt = 0;
HttpEntity entity = null;
while (userConfiguration.getMaxRetryAttempt() >= retryAttempt) {
try {
response = this.client.execute(this.request);
try {
entity = response.getEntity();
json = EntityUtils.toString(entity);
if (response.getStatusLine().getStatusCode() == 500 || response.getStatusLine().getStatusCode() == 408) {
throw new AvaTaxServerError((ErrorResult) JsonSerializer.DeserializeObject(json, ErrorResult.class), model);
}
if (response.getStatusLine().getStatusCode() != 200 && response.getStatusLine().getStatusCode() != 201) {
throw new AvaTaxClientException((ErrorResult) JsonSerializer.DeserializeObject(json, ErrorResult.class), model);
}

if (ContentType.getOrDefault(entity).getMimeType().equals("application/json")) {
obj = (T)JsonSerializer.DeserializeObject(json, typeToken.getType());
} else {
obj = (T)json;
}
break;
} catch (JsonParseException jsonParseException) {
ErrorResult errorResult = new ErrorResult();
int statusCode = response.getStatusLine().getStatusCode();
ArrayList<ErrorDetail> errors = new ArrayList<>();
ErrorDetail errorDetail = new ErrorDetail();
errorDetail.setDescription(json);
errors.add(errorDetail);

//set error info
ErrorInfo errorInfo = new ErrorInfo();
errorInfo.setMessage("The server returned " + statusCode + " but the response is in an unexpected format. See details for the complete response.");
errorInfo.setTarget(ErrorTargetCode.Unknown);
errorInfo.setDetails(errors);

errorResult.setError(errorInfo);
throw new AvaTaxClientException(errorResult, model);
} finally {
response.close();
}
} catch (AvaTaxServerError | ConnectTimeoutException ex) {
if (retryAttempt == userConfiguration.getMaxRetryAttempt()) {
throw ex;
}
retryAttempt++;
TimeUnit.SECONDS.sleep((long) (2 * retryAttempt));
}
} catch (JsonParseException jsonParseException) {
ErrorResult errorResult = new ErrorResult();
int statusCode = response.getStatusLine().getStatusCode();
ArrayList<ErrorDetail> errors = new ArrayList<>();
ErrorDetail errorDetail = new ErrorDetail();
errorDetail.setDescription(json);
errors.add(errorDetail);

//set error info
ErrorInfo errorInfo = new ErrorInfo();
errorInfo.setMessage("The server returned " + statusCode + " but the response is in an unexpected format. See details for the complete response.");
errorInfo.setTarget(ErrorTargetCode.Unknown);
errorInfo.setDetails(errors);

errorResult.setError(errorInfo);
throw new AvaTaxClientException(errorResult, model);
} finally {
response.close();
}

return obj;
}

private void buildRequest(HttpRequestBase baseRequest) {
addTimeOutIfRequired(baseRequest);


String clientId = String.format("%s; %s; %s; %s; %s", appName, appVersion, "JavaRestClient", "21.3.1", machineName);
String clientId = String.format("%s; %s; %s; %s; %s", appName, appVersion, "JavaRestClient", "21.3.2", machineName);
baseRequest.setHeader(AvaTaxConstants.XClientHeader, clientId);
}

private void addTimeOutIfRequired( HttpRequestBase baseRequest ) {
private void addTimeOutIfRequired(HttpRequestBase baseRequest) {
RequestConfig userConfig = getUserConfig();
if (isTimeOutMissing(userConfig)) {
addTimeOut(baseRequest, userConfig);
}
}

private boolean isTimeOutMissing( RequestConfig userConfig ) {
private boolean isTimeOutMissing(RequestConfig userConfig) {
if (userConfig == null) {
return true;
}

// Only override user config if user did not explicitly set a timeout
return userConfig.getConnectionRequestTimeout() == -1 || userConfig.getConnectTimeout() == -1 || userConfig.getSocketTimeout() == -1;
}

private void addTimeOut( HttpRequestBase baseRequest, RequestConfig userConfig ) {
int timeOut = 120_000;

private void addTimeOut(HttpRequestBase baseRequest, RequestConfig userConfig) {
// conversion to milliseconds
int timeOut = userConfiguration.getTimeOutInMinute() * 60 * 1000;
RequestConfig.Builder builder;
if (userConfig != null) {
builder = RequestConfig.copy(userConfig);
Expand All @@ -179,10 +195,9 @@ private void addTimeOut( HttpRequestBase baseRequest, RequestConfig userConfig )

private RequestConfig getUserConfig() {
if (client instanceof Configurable) {
Configurable configurable = (Configurable)client;
Configurable configurable = (Configurable) client;
return configurable.getConfig();
}

return null;
}
}
}
40 changes: 34 additions & 6 deletions src/main/java/net/avalara/avatax/rest/client/RestCallFactory.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.avalara.avatax.rest.client;

import com.google.gson.reflect.TypeToken;
import net.avalara.avatax.rest.client.models.UserConfiguration;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;

Expand All @@ -14,6 +15,7 @@ public class RestCallFactory {
private int proxyPort;
private String proxySchema;
private HttpClientBuilder httpClientBuilder;
private UserConfiguration userConfiguration;

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl) {
this.appName = appName;
Expand All @@ -22,6 +24,11 @@ public RestCallFactory(String appName, String appVersion, String machineName, St
this.environmentUrl = environmentUrl;
}

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl);
setUserConfig(userConfiguration);
}

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl, HttpClientBuilder httpClientBuilder) {
this.appName = appName;
this.appVersion = appVersion;
Expand All @@ -30,33 +37,54 @@ public RestCallFactory(String appName, String appVersion, String machineName, St
this.httpClientBuilder = httpClientBuilder;
}

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl, HttpClientBuilder httpClientBuilder, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl, httpClientBuilder);
setUserConfig(userConfiguration);
}

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl, String proxyHost, int proxyPort, String proxySchema) {
this(appName, appVersion, machineName, environmentUrl);
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxySchema = proxySchema;
}

public RestCallFactory(String appName, String appVersion, String machineName, String environmentUrl, String proxyHost, int proxyPort, String proxySchema, UserConfiguration userConfiguration) {
this(appName, appVersion, machineName, environmentUrl);
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxySchema = proxySchema;
setUserConfig(userConfiguration);
}

public void setUserConfig(UserConfiguration userConfiguration) {
if (userConfiguration == null) {
this.userConfiguration = new UserConfiguration();
} else {
this.userConfiguration = userConfiguration;
}
}

public <T> RestCall<T> createRestCall(String method, AvaTaxPath path, Object model, TypeToken<T> typeToken) {
if (header != null) {
if (proxyHost == null) {
if (httpClientBuilder == null) {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken, userConfiguration);
} else {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken, httpClientBuilder);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken, httpClientBuilder, userConfiguration);
}
} else {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken, proxyHost, proxyPort, proxySchema);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, header, method, path, model, typeToken, proxyHost, proxyPort, proxySchema, userConfiguration);
}
} else {
if (proxyHost == null) {
if (httpClientBuilder == null) {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, userConfiguration);
} else {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, httpClientBuilder, userConfiguration);
}
} else {
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, proxyHost, proxyPort, proxySchema);
return new RestCall<T>(appName, appVersion, machineName, environmentUrl, method, path, model, typeToken, proxyHost, proxyPort, proxySchema, userConfiguration);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ public enum BatchStatus {
/**
*
*/
Processing(8);
Processing(8),

/**
*
*/
Cancelling(9);

private int value;
private static HashMap map = new HashMap<>();
Expand Down
Loading