completed initial setup

This commit is contained in:
2025-06-16 18:13:20 +02:00
parent b435c2e5f5
commit eee746a5d8
34 changed files with 817 additions and 3 deletions

View File

@@ -0,0 +1,195 @@
package zw.qantra.tm.rest;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import zw.qantra.tm.exceptions.RestTemplateResponseErrorHandler;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/*
* Rest service that facilitates communication between services. Authentication
* is either based on client credentials, user credentials or is open. User credentials
* are only available for registered users
* */
@Service
@RequiredArgsConstructor
public class RestService {
Logger logger = LoggerFactory.getLogger(this.getClass().toString());
@Autowired
private Gson gson;
public final RestTemplate restTemplate;
public RestService() {
this.restTemplate = new RestTemplate(
new BufferingClientHttpRequestFactory(
new SimpleClientHttpRequestFactory()
)
);
this.restTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
// bootstrap rest template
List<ClientHttpRequestInterceptor> interceptors
= this.restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new RestTemplateInterceptor(gson));
this.restTemplate.setInterceptors(interceptors);
}
public String getUserToken(){
String token = "Utils.getToken()";
logger.info(token);
return token;
}
// client token is retrieved from open ID identity provider and
// cached for 20 days for easy reuse.
// todo: definitely not the best way to do this, tried implementing caching but
// that needs a bit of time to do correctly
public String getClientToken(){
logger.info("Getting client token");
MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
payload.add("grant_type", "client_credentials");
Map tokenResponse = getToken(payload);
assert tokenResponse != null;
String clientToken = (String) tokenResponse.get("access_token");
logger.info("client access token", "log", clientToken);
return clientToken;
}
public Map getToken(MultiValueMap payload){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
return this.restTemplate.postForObject("tokenUrl", entity, Map.class);
}
public <T> T getAsClient(String path, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(getClientToken());
HttpEntity entity = new HttpEntity<>(headers);
return this.restTemplate.getForObject(path, clazz, entity);
}
public <T> ResponseEntity<T> getExchangeAsClient(String path, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(getClientToken());
HttpEntity entity = new HttpEntity<>(headers);
return this.restTemplate.exchange(path, HttpMethod.GET, entity, clazz);
}
public <T> ResponseEntity<T> postAsClient(String path, Object payload, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBearerAuth(getClientToken());
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
ResponseEntity responseEntity = this.restTemplate.postForEntity(path, entity, clazz);
return responseEntity;
}
public <T> T postAs(String path, Object payload, HttpHeaders headers, Class<T> clazz){
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
return this.restTemplate.postForObject(path, entity, clazz);
}
public <T> T post(String path, Object payload, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBearerAuth(getUserToken());
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
T t = this.restTemplate.postForObject(path, entity, clazz);
return t;
}
public <T> T postWithToken(String token , String path, Object payload, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBearerAuth(token);
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
T t = this.restTemplate.postForObject(path, entity, clazz);
return t;
}
public <T> T postFormData(String path, MultiValueMap<String, Object> payload, Class<T> clazz)
{
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(payload, headers);
return this.restTemplate.postForEntity(path, request, clazz).getBody();
}
public <T> T get(String path, Type clazz){
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(getUserToken());
HttpEntity entity = new HttpEntity<>(headers);
ResponseEntity<String> responseEntity = this.restTemplate.exchange(path, HttpMethod.GET, entity, String.class);
T response = gson.fromJson(responseEntity.getBody(), clazz);
return response;
}
// make post request to endpoint without bearer auth
public <T> T postNoAuth(String path, Object payload, Class<T> clazz){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
T t = this.restTemplate.postForObject(path, entity, clazz);
return t;
}
// make post request to endpoint without bearer auth
public <T> T postWithExternalAuth(String path, Object payload, HttpHeaders headers, Class<T> clazz){
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
// build the request
HttpEntity entity = new HttpEntity<>(payload, headers);
T t = this.restTemplate.postForObject(path, entity, clazz);
return t;
}
// make get request to endpoint without bearer auth
public <T> T getNoAuth(String path, Class<T> clazz){
return this.restTemplate.getForObject(path, clazz);
}
public <T> ResponseEntity<?> exchangeGetNoAuth(String path, HttpEntity<?> httpEntity, Class<?> clazz, String pathVariable) {
return this.restTemplate.exchange(path, HttpMethod.GET, httpEntity, clazz, pathVariable);
}
}

View File

@@ -0,0 +1,72 @@
package zw.qantra.tm.rest;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.stream.Collectors;
@RequiredArgsConstructor
public class RestTemplateInterceptor
implements ClientHttpRequestInterceptor {
private final Logger logger = LoggerFactory.getLogger(getClass().getName());
private final Gson gson;
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] reqBody,
ClientHttpRequestExecution execution) throws IOException {
String requestBody = new String(reqBody, StandardCharsets.UTF_8);
if(!isJSONValid(requestBody)) requestBody = toBasicJson(requestBody);
// we don't log file data
if(request.getHeaders().getContentLength() < 10000){
logger.info("Request: "
+ request.getMethod() + ": "
+ request.getURI(), "http", gson.fromJson(requestBody, HashMap.class));
}
ClientHttpResponse response = execution.execute(request, reqBody);
InputStreamReader isr = new InputStreamReader(response.getBody());
String body = new BufferedReader(isr).lines()
.collect(Collectors.joining("\n"));
try{
logger.info("Response body: {}", "http", gson.fromJson(body, HashMap.class));
}catch (Exception exception){
logger.info("Problem serializing resp: {}", "http", exception.getMessage());
}
return response;
}
public String toBasicJson(String string){
HashMap map = new HashMap();
map.put("log", string);
return gson.toJson(map);
}
public boolean isJSONValid(String test) {
try {
new JSONObject(test);
} catch (JSONException ex) {
try {
new JSONArray(test);
} catch (JSONException ex1) {
return false;
}
}
return true;
}
}