Skip to content

Commit 5e33aaa

Browse files
author
Gerald Unterrainer
committed
Merge branch 'develop'
2 parents 4d15c82 + eff5285 commit 5e33aaa

File tree

17 files changed

+503
-51
lines changed

17 files changed

+503
-51
lines changed

pom.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<modelVersion>4.0.0</modelVersion>
1212
<artifactId>rest-client</artifactId>
13-
<version>0.0.2</version>
13+
<version>0.0.3</version>
1414
<name>RestClient</name>
1515
<packaging>jar</packaging>
1616

@@ -22,10 +22,15 @@
2222
</properties>
2323

2424
<dependencies>
25+
<dependency>
26+
<groupId>info.unterrainer.commons</groupId>
27+
<artifactId>http-server</artifactId>
28+
<version>0.2.21</version>
29+
</dependency>
2530
<dependency>
2631
<groupId>info.unterrainer.commons</groupId>
2732
<artifactId>serialization</artifactId>
28-
<version>0.1.3</version>
33+
<version>0.1.4</version>
2934
</dependency>
3035
<dependency>
3136
<groupId>com.squareup.okhttp3</groupId>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import com.fasterxml.jackson.core.type.TypeReference;
7+
import com.fasterxml.jackson.databind.JavaType;
8+
9+
import info.unterrainer.commons.httpserver.jsons.ListJson;
10+
import info.unterrainer.commons.restclient.RestClient.HttpGetCall;
11+
import lombok.AccessLevel;
12+
import lombok.RequiredArgsConstructor;
13+
14+
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
15+
public abstract class BaseBuilder<T, R extends BaseBuilder<T, R>> {
16+
17+
protected enum Retry {
18+
ONCE,
19+
SHORT,
20+
ENDURING
21+
}
22+
23+
protected final RestClient client;
24+
protected final Class<?> type;
25+
26+
protected String url;
27+
protected JavaType javaType;
28+
protected TypeReference<?> typeReference;
29+
protected Map<String, String> headers = new HashMap<>();
30+
protected Retry retry = Retry.ONCE;
31+
32+
@SuppressWarnings("unchecked")
33+
public R url(final String url) {
34+
this.url = url;
35+
return (R) this;
36+
}
37+
38+
@SuppressWarnings("unchecked")
39+
public R isListJson() {
40+
javaType = client.jsonMapper.getTypeFactory().constructParametricType(ListJson.class, type);
41+
return (R) this;
42+
}
43+
44+
@SuppressWarnings("unchecked")
45+
public R addHeader(final String key, final String value) {
46+
headers.put(key, value);
47+
return (R) this;
48+
}
49+
50+
@SuppressWarnings("unchecked")
51+
public R retryShort() {
52+
retry = Retry.SHORT;
53+
return (R) this;
54+
}
55+
56+
@SuppressWarnings("unchecked")
57+
public R retryEnduring() {
58+
retry = Retry.ENDURING;
59+
return (R) this;
60+
}
61+
62+
protected abstract HttpGetCall<T> provideCall(String url, Class<T> type, Map<String, String> headers);
63+
64+
protected abstract HttpGetCall<T> provideJavaTypeCall(String url, JavaType javaType, Map<String, String> headers);
65+
66+
public T execute() {
67+
switch (retry) {
68+
case SHORT:
69+
return client.retryShort(provide(url, type, javaType, headers));
70+
case ENDURING:
71+
return client.retryEnduring(provide(url, type, javaType, headers));
72+
default:
73+
return client.once(provide(url, type, javaType, headers));
74+
}
75+
}
76+
77+
@SuppressWarnings("unchecked")
78+
private HttpGetCall<T> provide(final String url, final Class<?> type, final JavaType javaType,
79+
final Map<String, String> headers) {
80+
if (javaType != null)
81+
return provideJavaTypeCall(url, javaType, headers);
82+
return provideCall(url, (Class<T>) type, headers);
83+
}
84+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
import java.util.Map;
4+
5+
import com.fasterxml.jackson.databind.JavaType;
6+
7+
import info.unterrainer.commons.restclient.RestClient.HttpGetCall;
8+
9+
public class BaseGetBuilder<T, R> extends BaseBuilder<T, BaseGetBuilder<T, R>> {
10+
11+
BaseGetBuilder(final RestClient client, final Class<?> type) {
12+
super(client, type);
13+
}
14+
15+
@SuppressWarnings("unchecked")
16+
@Override
17+
protected HttpGetCall<T> provideCall(final String url, final Class<T> type, final Map<String, String> headers) {
18+
return client -> {
19+
String r = client.getPlain(url, StringParam.builder().parameters(headers).build());
20+
if (String.class.isAssignableFrom(type))
21+
return (T) r;
22+
return client.jsonMapper.fromStringTo(type, r);
23+
};
24+
}
25+
26+
@Override
27+
protected HttpGetCall<T> provideJavaTypeCall(final String url, final JavaType javaType,
28+
final Map<String, String> headers) {
29+
return client -> {
30+
String r = client.getPlain(url, StringParam.builder().parameters(headers).build());
31+
return client.jsonMapper.fromStringTo(javaType, r);
32+
};
33+
}
34+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
public abstract class BaseKeycloakBuilder<T, R extends BaseKeycloakBuilder<T, R>> extends BaseBuilder<T, R> {
4+
5+
private final KeycloakContext kcc;
6+
7+
BaseKeycloakBuilder(final RestClient client, final Class<?> type, final KeycloakContext kcc) {
8+
super(client, type);
9+
this.kcc = kcc;
10+
}
11+
12+
@Override
13+
public T execute() {
14+
kcc.update(client);
15+
return super.execute();
16+
}
17+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
import java.util.Map;
4+
5+
import com.fasterxml.jackson.databind.JavaType;
6+
7+
import info.unterrainer.commons.restclient.RestClient.HttpGetCall;
8+
9+
public class BasePostBuilder<T, R> extends BaseBuilder<T, BasePostBuilder<T, R>> {
10+
11+
protected String mediaType;
12+
protected String body;
13+
14+
BasePostBuilder(final RestClient client, final Class<?> type) {
15+
super(client, type);
16+
}
17+
18+
@SuppressWarnings("unchecked")
19+
public R mediaType(final String mediaType) {
20+
this.mediaType = mediaType;
21+
return (R) this;
22+
}
23+
24+
@SuppressWarnings("unchecked")
25+
public R body(final String body) {
26+
this.body = body;
27+
return (R) this;
28+
}
29+
30+
@SuppressWarnings("unchecked")
31+
@Override
32+
protected HttpGetCall<T> provideCall(final String url, final Class<T> type, final Map<String, String> headers) {
33+
return client -> {
34+
String r = client.postPlain(url, StringParam.builder().parameters(headers).build(), mediaType, body);
35+
if (String.class.isAssignableFrom(type))
36+
return (T) r;
37+
return client.jsonMapper.fromStringTo(type, r);
38+
};
39+
}
40+
41+
@Override
42+
protected HttpGetCall<T> provideJavaTypeCall(final String url, final JavaType javaType,
43+
final Map<String, String> headers) {
44+
return client -> {
45+
String r = client.postPlain(url, StringParam.builder().parameters(headers).build(), mediaType, body);
46+
return client.jsonMapper.fromStringTo(javaType, r);
47+
};
48+
}
49+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
public class GetBuilder<T> extends BaseGetBuilder<T, GetBuilder<T>> {
4+
5+
GetBuilder(final RestClient client, final Class<?> type) {
6+
super(client, type);
7+
}
8+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
public class GetKeycloakBuilder<T> extends BaseGetBuilder<T, GetKeycloakBuilder<T>> {
4+
5+
private KeycloakContext kcc;
6+
7+
GetKeycloakBuilder(final RestClient client, final Class<?> type, final KeycloakContext kcc) {
8+
super(client, type);
9+
this.kcc = kcc;
10+
}
11+
12+
@Override
13+
public T execute() {
14+
kcc.update(client);
15+
addHeader("Authorization", "Bearer " + kcc.getAccessToken());
16+
return super.execute();
17+
}
18+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
import java.io.UnsupportedEncodingException;
4+
import java.net.URLEncoder;
5+
6+
import info.unterrainer.commons.restclient.jsons.TokenResponseJson;
7+
import lombok.Getter;
8+
import lombok.RequiredArgsConstructor;
9+
import lombok.extern.slf4j.Slf4j;
10+
11+
@Slf4j
12+
@RequiredArgsConstructor
13+
public class KeycloakContext {
14+
15+
private final String keycloakUrl;
16+
private final String userName;
17+
private final String password;
18+
private final String clientId;
19+
private final String clientSecret;
20+
@Getter
21+
private String accessToken;
22+
@Getter
23+
private String refreshToken;
24+
@Getter
25+
private Long refreshTimestamp;
26+
27+
public <T> GetKeycloakBuilder<T> get(final RestClient client, final Class<?> type) {
28+
return new GetKeycloakBuilder<>(client, type, this);
29+
}
30+
31+
public <T> PostKeycloakBuilder<T> post(final RestClient client, final Class<?> type) {
32+
return new PostKeycloakBuilder<>(client, type, this);
33+
}
34+
35+
void update(final RestClient client) {
36+
long now = System.currentTimeMillis();
37+
38+
log.debug("now: [{}]", now);
39+
log.debug("accessToken: [{}]", accessToken);
40+
log.debug("refreshTimestamp: [{}]", refreshTimestamp);
41+
42+
if (refreshTimestamp != null) {
43+
long delta = refreshTimestamp - now;
44+
log.debug("valid for another: [{}]s", (delta - delta % 1000) / 1000);
45+
}
46+
47+
if (accessToken == null || refreshTimestamp == null || now > refreshTimestamp) {
48+
String cs = "";
49+
if (clientSecret != null)
50+
try {
51+
cs = "&client_secret=" + URLEncoder.encode(clientSecret, "UTF-8");
52+
} catch (UnsupportedEncodingException e1) {
53+
log.error("Could not URLEncode clientSecret: [{}]", clientSecret);
54+
}
55+
56+
String encUserName = null;
57+
try {
58+
encUserName = URLEncoder.encode(userName, "UTF-8");
59+
} catch (UnsupportedEncodingException e) {
60+
log.error("Could not URLEncode userName: [{}]", userName);
61+
}
62+
63+
String encPassword = null;
64+
try {
65+
encPassword = URLEncoder.encode(password, "UTF-8");
66+
} catch (UnsupportedEncodingException e) {
67+
log.error("Could not URLEncode password: [{}]", password);
68+
}
69+
70+
String body = "client_id=" + clientId + cs + "&grant_type=password&username=" + encUserName + "&password="
71+
+ encPassword;
72+
log.debug("body: [{}]", body);
73+
74+
TokenResponseJson response = null;
75+
response = client.<TokenResponseJson>post(TokenResponseJson.class)
76+
.addHeader("Content-Type", "application/x-www-form-urlencoded")
77+
.addHeader("Accept", "application/json")
78+
.url(keycloakUrl)
79+
.retryShort()
80+
.mediaType("application/x-www-form-urlencoded")
81+
.body(body)
82+
.execute();
83+
if (response == null)
84+
return;
85+
86+
accessToken = response.getAccessToken();
87+
refreshToken = response.getRefreshToken();
88+
refreshTimestamp = now + response.getExpiresIn() * 1000L;
89+
}
90+
}
91+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
public class PostBuilder<T> extends BasePostBuilder<T, PostBuilder<T>> {
4+
5+
PostBuilder(final RestClient client, final Class<?> type) {
6+
super(client, type);
7+
}
8+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package info.unterrainer.commons.restclient;
2+
3+
public class PostKeycloakBuilder<T> extends BasePostBuilder<T, PostKeycloakBuilder<T>> {
4+
5+
private KeycloakContext kcc;
6+
7+
PostKeycloakBuilder(final RestClient client, final Class<?> type, final KeycloakContext kcc) {
8+
super(client, type);
9+
this.kcc = kcc;
10+
}
11+
12+
@Override
13+
public T execute() {
14+
kcc.update(client);
15+
addHeader("Authorization", "Bearer " + kcc.getAccessToken());
16+
return super.execute();
17+
}
18+
}

0 commit comments

Comments
 (0)