Skip to content

Commit 7b3fca7

Browse files
committed
Initial commit
1 parent 401ddbc commit 7b3fca7

27 files changed

+1235
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package com.taboola.rest.api;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collection;
5+
import java.util.List;
6+
import java.util.Objects;
7+
import java.util.stream.Collectors;
8+
9+
import org.apache.logging.log4j.LogManager;
10+
import org.apache.logging.log4j.Logger;
11+
12+
import com.taboola.rest.api.internal.CommunicationFactory;
13+
import com.taboola.rest.api.internal.config.CommunicationConfig;
14+
import com.taboola.rest.api.internal.config.SerializationConfig;
15+
import com.taboola.rest.api.internal.config.UserAgentHeader;
16+
import com.taboola.rest.api.model.RequestHeader;
17+
18+
/**
19+
* Created by vladi.m
20+
* Date 23/06/2021
21+
* Time 16:42
22+
* Copyright Taboola
23+
*/
24+
public class RestAPIClient {
25+
26+
private static final Logger logger = LogManager.getLogger(RestAPIClient.class);
27+
28+
private final CommunicationFactory communicator;
29+
30+
private RestAPIClient(CommunicationFactory communicator) {
31+
this.communicator = communicator;
32+
}
33+
34+
public <E> E createRetrofitEndpoint(Class<E> endpointClazz) {
35+
Objects.requireNonNull(endpointClazz, "clazz");
36+
logger.debug("creating endpoint using retrofit for class [{}]", endpointClazz::toString);
37+
return communicator.createRetrofitEndpoint(endpointClazz);
38+
}
39+
40+
public static RestAPIClientBuilder builder() {
41+
return new RestAPIClientBuilder();
42+
}
43+
44+
public static class RestAPIClientBuilder {
45+
private static final String VERSION = "1.0.0";
46+
private static final Integer DEFAULT_MAX_IDLE_CONNECTIONS = 5;
47+
private static final Long DEFAULT_KEEP_ALIVE_DURATION_MILLIS = 300_000L;
48+
private static final SerializationConfig DEFAULT_SERIALIZATION_CONFIG = new SerializationConfig();
49+
private static final String DEFAULT_REST_API_VERSION = "UNDEFINED";
50+
private static final String DEFAULT_USER_AGENT_SUFFIX = "UNDEFINED";
51+
private static final String DEFAULT_USER_AGENT_PREFIX = "UNDEFINED";
52+
53+
private String baseUrl;
54+
private Long writeTimeoutMillis;
55+
private Long connectionTimeoutMillis;
56+
private Long readTimeoutMillis;
57+
private Integer maxIdleConnections;
58+
private Long keepAliveDurationMillis;
59+
private Boolean debug;
60+
private SerializationConfig serializationConfig;
61+
private Collection<RequestHeader> headers;
62+
private String userAgentPrefix;
63+
private String userAgentSuffix;
64+
private String restAPIVersion;
65+
66+
public RestAPIClientBuilder setBaseUrl(String baseUrl) {
67+
this.baseUrl = baseUrl;
68+
return this;
69+
}
70+
71+
public RestAPIClientBuilder setUserAgentSuffix(String userAgentSuffix) {
72+
this.userAgentSuffix = userAgentSuffix;
73+
return this;
74+
}
75+
76+
public RestAPIClientBuilder setUserAgentPrefix(String userAgentPrefix) {
77+
this.userAgentPrefix = userAgentPrefix;
78+
return this;
79+
}
80+
81+
public RestAPIClientBuilder setConnectionTimeoutMillis(Long connectionTimeoutMillis) {
82+
this.connectionTimeoutMillis = connectionTimeoutMillis;
83+
return this;
84+
}
85+
86+
public RestAPIClientBuilder setReadTimeoutMillis(Long readTimeoutMillis) {
87+
this.readTimeoutMillis = readTimeoutMillis;
88+
return this;
89+
}
90+
91+
public RestAPIClientBuilder setWriteTimeoutMillis(Long writeTimeoutMillis) {
92+
this.writeTimeoutMillis = writeTimeoutMillis;
93+
return this;
94+
}
95+
96+
public RestAPIClientBuilder setMaxIdleConnections(Integer maxIdleConnections) {
97+
this.maxIdleConnections = maxIdleConnections;
98+
return this;
99+
}
100+
101+
public RestAPIClientBuilder setKeepAliveDurationMillis(Long keepAliveDurationMillis) {
102+
this.keepAliveDurationMillis = keepAliveDurationMillis;
103+
return this;
104+
}
105+
106+
public RestAPIClientBuilder setDebug(Boolean debug) {
107+
this.debug = debug;
108+
return this;
109+
}
110+
111+
public RestAPIClientBuilder setSerializationConfig(SerializationConfig serializationConfig) {
112+
this.serializationConfig = serializationConfig;
113+
return this;
114+
}
115+
116+
public RestAPIClientBuilder setHeaders(Collection<RequestHeader> headers){
117+
this.headers = headers;
118+
return this;
119+
}
120+
121+
public RestAPIClientBuilder setAPIVersion(String restAPIVersion) {
122+
this.restAPIVersion = restAPIVersion;
123+
return this;
124+
}
125+
126+
public RestAPIClient build() {
127+
organizeState();
128+
String finalUserAgent = String.format("%s/%s/%s (%s)", userAgentPrefix, restAPIVersion, VERSION, userAgentSuffix);
129+
Collection<RequestHeader> headers = getAllHeaders(this.headers, finalUserAgent);
130+
CommunicationConfig config = new CommunicationConfig(baseUrl, connectionTimeoutMillis, readTimeoutMillis, writeTimeoutMillis, maxIdleConnections,
131+
keepAliveDurationMillis, headers, debug);
132+
return new RestAPIClient(new CommunicationFactory(config, serializationConfig));
133+
}
134+
135+
private Collection<RequestHeader> getAllHeaders(Collection<RequestHeader> clientHeaders, String finalUserAgent) {
136+
List<RequestHeader> headers = new ArrayList<>();
137+
if (clientHeaders != null) {
138+
headers.addAll(clientHeaders.stream().
139+
filter(Objects::nonNull)
140+
.collect(Collectors.toList()));
141+
}
142+
headers.add(new UserAgentHeader(finalUserAgent));
143+
return headers;
144+
}
145+
146+
private void organizeState() {
147+
if (baseUrl == null) {
148+
throw new IllegalStateException("Missing base url");
149+
}
150+
151+
if (connectionTimeoutMillis == null) {
152+
connectionTimeoutMillis = 0L;
153+
}
154+
155+
if (readTimeoutMillis == null) {
156+
readTimeoutMillis = 0L;
157+
}
158+
159+
if (writeTimeoutMillis == null) {
160+
writeTimeoutMillis = 0L;
161+
}
162+
163+
if (maxIdleConnections == null) {
164+
maxIdleConnections = DEFAULT_MAX_IDLE_CONNECTIONS;
165+
}
166+
167+
if (keepAliveDurationMillis == null) {
168+
keepAliveDurationMillis = DEFAULT_KEEP_ALIVE_DURATION_MILLIS;
169+
}
170+
171+
if (userAgentSuffix == null) {
172+
userAgentSuffix = DEFAULT_USER_AGENT_SUFFIX;
173+
}
174+
175+
if(userAgentPrefix == null) {
176+
userAgentPrefix = DEFAULT_USER_AGENT_PREFIX;
177+
}
178+
179+
if(restAPIVersion == null) {
180+
restAPIVersion = DEFAULT_REST_API_VERSION;
181+
}
182+
183+
if (debug == null) {
184+
debug = false;
185+
}
186+
187+
if (serializationConfig == null) {
188+
serializationConfig = DEFAULT_SERIALIZATION_CONFIG;
189+
}
190+
}
191+
}
192+
193+
194+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.taboola.rest.api.annotations;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* Final fields are set once, when creating the resource, and become read-only afterwards.
7+
*
8+
* Created by vladi
9+
* Date: 1/15/2018
10+
* Time: 10:18 PM
11+
* By Taboola
12+
*/
13+
@Documented
14+
@Retention(RetentionPolicy.RUNTIME)
15+
@Target({ElementType.FIELD})
16+
public @interface Final {
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.taboola.rest.api.annotations;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* Read-only fields are fields that should never be sent to the server, and will appear only when fetching a resource.
7+
*
8+
* Created by vladi
9+
* Date: 1/15/2018
10+
* Time: 10:17 PM
11+
* By Taboola
12+
*/
13+
@Documented
14+
@Retention(RetentionPolicy.RUNTIME)
15+
@Target({ElementType.FIELD})
16+
public @interface ReadOnly {
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.taboola.rest.api.annotations;
2+
3+
import java.lang.annotation.*;
4+
5+
/**
6+
* Required fields are fields that must be sent to the server when creating a new resource.
7+
*
8+
* Created by vladi
9+
* Date: 1/15/2018
10+
* Time: 10:17 PM
11+
* By Taboola
12+
*/
13+
@Documented
14+
@Retention(RetentionPolicy.RUNTIME)
15+
@Target({ElementType.FIELD})
16+
public @interface Required {
17+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.taboola.rest.api.exceptions;
2+
3+
4+
/**
5+
* Created by vladi
6+
* Date: 10/30/2017
7+
* Time: 11:08 PM
8+
* By Taboola
9+
*/
10+
public class RestAPIConnectivityException extends RestAPIException {
11+
12+
private static final String ERROR_STR = "Failed to perform API call, might be due to internet connectivity issues";
13+
private static final String ERROR_STR_WITH_RESPONSE_CODE = "Failed to perform API call with response code [%d], might be due to internet connectivity issues";
14+
15+
public RestAPIConnectivityException() {
16+
super(ERROR_STR);
17+
}
18+
19+
public RestAPIConnectivityException(Throwable cause) {
20+
super(cause, ERROR_STR);
21+
}
22+
23+
public RestAPIConnectivityException(int responseCode) {
24+
super(ERROR_STR_WITH_RESPONSE_CODE, responseCode);
25+
}
26+
27+
public RestAPIConnectivityException(Throwable cause, int responseCode) {
28+
super(cause, ERROR_STR_WITH_RESPONSE_CODE, responseCode);
29+
}
30+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.taboola.rest.api.exceptions;
2+
3+
import com.taboola.rest.api.model.APIError;
4+
5+
/**
6+
* Created by vladi
7+
* Date: 9/13/2017
8+
* Time: 12:23 AM
9+
* By Taboola
10+
*/
11+
public abstract class RestAPIException extends RuntimeException {
12+
13+
private APIError error = APIError.EMPTY;
14+
15+
public RestAPIException(Throwable cause, String message, Object ... params) {
16+
super(String.format(message, params), cause);
17+
}
18+
19+
public RestAPIException(String message, Object ... params) {
20+
super(String.format(message, params));
21+
}
22+
23+
public RestAPIException(APIError error, String message, Object ... params) {
24+
super(String.format(message + parseError(error), params));
25+
this.error = error;
26+
}
27+
28+
public RestAPIException(APIError error, String message, Throwable t, Object ... params) {
29+
super(String.format(message + parseError(error), params), t);
30+
this.error = error;
31+
}
32+
33+
private static String parseError(APIError error) {
34+
if(error == null || APIError.EMPTY.equals(error)) {
35+
return "";
36+
}
37+
38+
return String.format(". Response payload status [%s], message [%s], offending field [%s], message code [%s]", error.getHttpStatus(), error.getMessage(), error.getOffendingField(), error.getMessageCode());
39+
}
40+
41+
public APIError getError() {
42+
return error;
43+
}
44+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.taboola.rest.api.exceptions;
2+
3+
import com.taboola.rest.api.model.APIError;
4+
5+
/**
6+
* Created by vladi
7+
* Date: 10/30/2017
8+
* Time: 11:12 PM
9+
* By Taboola
10+
*/
11+
public class RestAPIRequestException extends RestAPIException {
12+
13+
public RestAPIRequestException(String message, Object ... params) {
14+
super(message, params);
15+
}
16+
17+
public RestAPIRequestException(int responseCode, APIError error) {
18+
super(error, "Failed to perform API call with response code [%d]", responseCode);
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.taboola.rest.api.exceptions;
2+
3+
/**
4+
* Created by vladi
5+
* Date: 10/30/2017
6+
* Time: 10:51 PM
7+
* By Taboola
8+
*/
9+
public class RestAPIUnauthorizedException extends RestAPIException {
10+
11+
private static final String ERROR_STR = "Unauthorized, expired token or invalid credentials";
12+
13+
public RestAPIUnauthorizedException() {
14+
super(ERROR_STR);
15+
}
16+
17+
public RestAPIUnauthorizedException(Throwable cause) {
18+
super(cause, ERROR_STR);
19+
}
20+
}

0 commit comments

Comments
 (0)