Skip to content

Commit

Permalink
Fix API compatability between Spring 5 and 6
Browse files Browse the repository at this point in the history
Spring changed the API of ReponseEntity with 6.x so that code compiled
with Spring 5.x will not work anymore. As a workaround we use
getStatusCodeValue instead of getStatusCode to make the library work
with both spring versions.

Also cleanup error handling of CompletableFuture data loading

Closes #59
  • Loading branch information
derkoe committed Jan 13, 2023
1 parent 6dd4bae commit 48af72b
Showing 1 changed file with 68 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.annotation.JsonProperty;
Expand Down Expand Up @@ -178,16 +177,17 @@ public void setInitialCacheTimestamp(long initialCacheTimestamp) {
* @return if async enabled
*/
public boolean isAsync() {
return async;
return async;
}

/**
* Use async loading - all operations will be performed in a single threaded {@link ExecutorService}.
* Use async loading - all operations will be performed in a single threaded
* {@link ExecutorService}.
*
* @param async if true loading will be performed asynchronously
*/
public void setAsync(boolean async) {
this.async = async;
this.async = async;
}

/**
Expand All @@ -203,7 +203,14 @@ public Set<Locale> getExistingLocales() {
* This does not clear the cached translations.
*/
public void reloadExistingLocales() {
CompletableFuture<Void> loadTask = CompletableFuture.runAsync(() -> loadCodes(), executor);
CompletableFuture<Void> loadTask = CompletableFuture
.runAsync(this::loadCodes, executor)
.handle((val, e) -> {
if (e != null) {
logger.warn("Error reloading locales", e);
}
return val;
});
if (!async) {
loadTask.join();
}
Expand Down Expand Up @@ -359,14 +366,19 @@ private Properties loadTranslations(Locale locale, boolean reload) {
* loaded (optional)
*/
private void loadTranslation(Locale language, Properties properties, long timestamp) {
CompletableFuture<Map<Locale, String>> loadCodesTask = CompletableFuture.supplyAsync(() -> loadCodes());
CompletableFuture<Map<Locale, String>> loadCodesTask = CompletableFuture.supplyAsync(this::loadCodes);

CompletableFuture<Void> loadTask = loadCodesTask.thenCompose(locales -> {
String lang = existingLocales.get(language);
if (lang != null) {
return loadTranslation(lang, properties, timestamp);
return CompletableFuture.runAsync(() -> loadTranslation(lang, properties, timestamp), executor);
}
return CompletableFuture.completedStage(null);
}).handle((val, e) -> {
if (e != null) {
logger.warn("Error loading translation for locale " + language, e);
}
return val;
});

if (!async) {
Expand All @@ -381,76 +393,70 @@ private static String formatTimestampIso(long timestamp) {
return df.format(new Date(timestamp));
}

private CompletableFuture<Void> loadTranslation(String code, Properties properties, long timestamp) {
return CompletableFuture.runAsync(() -> {
String currentQuery = query;
if (timestamp > 0L) {
String timestampStr = formatTimestampIso(timestamp);
currentQuery += " AND (added:>=" + timestampStr + " OR changed:>=" + timestampStr + ")";
}
private void loadTranslation(String code, Properties properties, long timestamp) {
String currentQuery = query;
if (timestamp > 0L) {
String timestampStr = formatTimestampIso(timestamp);
currentQuery += " AND (added:>=" + timestampStr + " OR changed:>=" + timestampStr + ")";
}
RequestEntity<Void> request = RequestEntity
.get(baseUrl + "/api/translations/{project}/{component}/{languageCode}/units/?q={query}",
project, component, code, currentQuery)
.accept(MediaType.APPLICATION_JSON)
.build();

try {
RequestEntity<Void> request = RequestEntity
.get(baseUrl + "/api/translations/{project}/{component}/{languageCode}/units/?q={query}",
project, component, code, currentQuery)
.accept(MediaType.APPLICATION_JSON)
.build();

if (restTemplate == null) {
restTemplate = createRestTemplate();
}

UnitsResponse responseBody;
while (true) {
ResponseEntity<UnitsResponse> response = restTemplate.exchange(request, UnitsResponse.class);
responseBody = response.getBody();
if (!response.getStatusCode().is2xxSuccessful() || responseBody == null) {
logger.warn(String.format("Got empty or non-200 response (status=%s, body=%s)", response.getStatusCode(),
response.getBody()));
break;
}
if (restTemplate == null) {
restTemplate = createRestTemplate();
}

for (Unit unit : responseBody.results) {
properties.put(unit.code, unit.target[0]);
}
UnitsResponse body;
while (true) {
ResponseEntity<UnitsResponse> response = restTemplate.exchange(request, UnitsResponse.class);
body = response.getBody();
if (response.getStatusCodeValue() < 200 || response.getStatusCodeValue() >= 300 || body == null) {
logger.warn(String.format("Got empty or non-200 response (status=%s, body=%s)", response.getStatusCode(),
response.getBody()));
break;
}

if (responseBody.next == null) {
break;
}
for (Unit unit : body.results) {
properties.put(unit.code, unit.target[0]);
}

if (body.next == null) {
break;
}

request = RequestEntity.get(responseBody.next.toURI()).accept(MediaType.APPLICATION_JSON).build();
}
} catch (RestClientException | URISyntaxException e) {
logger.warn("Could not load translations (code=" + code + ")", e);
try {
request = RequestEntity.get(body.next.toURI()).accept(MediaType.APPLICATION_JSON).build();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}, executor);
}
}

private Map<Locale, String> loadCodes() {
if (existingLocales != null) {
return existingLocales;
}

try {
RequestEntity<Void> request = RequestEntity.get(baseUrl + "/api/projects/{project}/languages/", project)
.accept(MediaType.APPLICATION_JSON).build();
RequestEntity<Void> request = RequestEntity.get(baseUrl + "/api/projects/{project}/languages/", project)
.accept(MediaType.APPLICATION_JSON).build();

if (restTemplate == null) {
restTemplate = createRestTemplate();
}
if (restTemplate == null) {
restTemplate = createRestTemplate();
}

ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(request, LIST_MAP_STRING_OBJECT);
List<Map<String, Object>> body = response.getBody();
if (response.getStatusCode().is2xxSuccessful() && body != null) {
existingLocales = body.stream()
.filter(this::containsTranslations)
.map(this::extractCode)
.filter(Objects::nonNull)
.collect(Collectors.toMap(this::deriveLocaleFromCode, Function.identity()));
}
} catch (RestClientException e) {
logger.warn("Could not load languages", e);
ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(request, LIST_MAP_STRING_OBJECT);
List<Map<String, Object>> body = response.getBody();
if (response.getStatusCodeValue() >= 200 && response.getStatusCodeValue() < 300 && body != null) {
existingLocales = body.stream()
.filter(this::containsTranslations)
.map(this::extractCode)
.filter(Objects::nonNull)
.collect(Collectors.toMap(this::deriveLocaleFromCode, Function.identity()));
}

return existingLocales;
}

Expand Down

0 comments on commit 48af72b

Please sign in to comment.