Skip to content

Commit 7427897

Browse files
authored
Merge pull request #1051 from qbicsoftware/development
Prepare 1.9.0 release
2 parents b67bd74 + 496d009 commit 7427897

File tree

31 files changed

+1415
-78
lines changed

31 files changed

+1415
-78
lines changed

.github/workflows/build_package.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ jobs:
1515
steps:
1616
- name: Checkout repository
1717
uses: actions/checkout@v4
18-
- name: Set up JDK 17
18+
- name: Set up JDK 21
1919
uses: actions/setup-java@v4
2020
with:
2121
distribution: 'zulu'
22-
java-version: '17'
22+
java-version: '21'
2323
- name: Load local Maven repository cache
2424
uses: actions/cache@v4
2525
with:

.github/workflows/codeql-analysis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ jobs:
3838
steps:
3939
- name: Checkout repository
4040
uses: actions/checkout@v4
41-
- name: Set up JDK 17
41+
- name: Set up JDK 21
4242
uses: actions/setup-java@v4
4343
with:
4444
distribution: 'zulu'
45-
java-version: '17'
45+
java-version: '21'
4646
settings-path: ${{ github.workspace }}
4747

4848
- name: Load local Maven repository cache

.github/workflows/create-release.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ jobs:
1313
steps:
1414
- name: Checkout repository
1515
uses: actions/checkout@v4
16-
- name: Set up JDK 17
16+
- name: Set up JDK 21
1717
uses: actions/setup-java@v4
1818
with:
1919
distribution: 'zulu'
20-
java-version: '17'
20+
java-version: '21'
2121
settings-path: ${{ github.workspace }}
2222

2323
- name: Load local Maven repository cache

.github/workflows/nexus-publish-snapshots.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
steps:
1818
- name: Checkout repository
1919
uses: actions/checkout@v4
20-
- name: Set up JDK 17
20+
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:
2323
distribution: 'zulu'
24-
java-version: '17'
24+
java-version: '21'
2525
settings-path: ${{ github.workspace }}
2626

2727
- name: Load local Maven repository cache

.github/workflows/run_tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ jobs:
1515
steps:
1616
- name: Checkout repository
1717
uses: actions/checkout@v4
18-
- name: Set up JDK 17
18+
- name: Set up JDK 21
1919
uses: actions/setup-java@v4
2020
with:
2121
distribution: 'zulu'
22-
java-version: '17'
22+
java-version: '21'
2323
settings-path: ${{ github.workspace }}
2424

2525
- name: Load local Maven repository cache

.github/workflows/sonarcloud.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
steps:
1818
- name: Checkout repository
1919
uses: actions/checkout@v4
20-
- name: Set up JDK 17
20+
- name: Set up JDK 21
2121
uses: actions/setup-java@v4
2222
with:
2323
distribution: 'zulu'
24-
java-version: '17'
24+
java-version: '21'
2525
- name: Load local Maven repository cache
2626
uses: actions/cache@v4
2727
with:

domain-concept/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<artifactId>domain-concept</artifactId>
1313

1414
<properties>
15-
<maven.compiler.source>17</maven.compiler.source>
16-
<maven.compiler.target>17</maven.compiler.target>
15+
<maven.compiler.source>21</maven.compiler.source>
16+
<maven.compiler.target>21</maven.compiler.target>
1717
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1818
</properties>
1919

email-service-provider/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
<artifactId>email-service-provider</artifactId>
1414

1515
<properties>
16-
<maven.compiler.source>17</maven.compiler.source>
17-
<maven.compiler.target>17</maven.compiler.target>
16+
<maven.compiler.source>21</maven.compiler.source>
17+
<maven.compiler.target>21</maven.compiler.target>
1818
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1919
</properties>
2020
<dependencies>

finances-api/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
<artifactId>finances-api</artifactId>
1414

1515
<properties>
16-
<maven.compiler.source>17</maven.compiler.source>
17-
<maven.compiler.target>17</maven.compiler.target>
16+
<maven.compiler.source>21</maven.compiler.source>
17+
<maven.compiler.target>21</maven.compiler.target>
1818
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1919
</properties>
2020

finances-infrastructure/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<artifactId>finances-infrastructure</artifactId>
1313

1414
<properties>
15-
<maven.compiler.source>17</maven.compiler.source>
16-
<maven.compiler.target>17</maven.compiler.target>
15+
<maven.compiler.source>21</maven.compiler.source>
16+
<maven.compiler.target>21</maven.compiler.target>
1717
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1818
</properties>
1919
<dependencies>

identity-api/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
<artifactId>identity-api</artifactId>
1414

1515
<properties>
16-
<maven.compiler.source>17</maven.compiler.source>
17-
<maven.compiler.target>17</maven.compiler.target>
16+
<maven.compiler.source>21</maven.compiler.source>
17+
<maven.compiler.target>21</maven.compiler.target>
1818
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1919
</properties>
2020
<dependencies>

identity-infrastructure/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
</dependencies>
3131

3232
<properties>
33-
<maven.compiler.source>17</maven.compiler.source>
34-
<maven.compiler.target>17</maven.compiler.target>
33+
<maven.compiler.source>21</maven.compiler.source>
34+
<maven.compiler.target>21</maven.compiler.target>
3535
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3636
</properties>
3737

pom.xml

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
<packaging>pom</packaging>
3030

3131
<properties>
32-
<java.version>17</java.version>
32+
<java.version>21</java.version>
3333
<vaadin.version>24.4.13</vaadin.version>
34-
<maven.compiler.source>17</maven.compiler.source>
35-
<maven.compiler.target>17</maven.compiler.target>
34+
<maven.compiler.source>21</maven.compiler.source>
35+
<maven.compiler.target>21</maven.compiler.target>
3636
<jakarta.persistence.version>3.2.0</jakarta.persistence.version>
3737
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3838
<jackson.version>2.18.1</jackson.version>
@@ -244,6 +244,7 @@
244244
<useModulePath>false</useModulePath>
245245
<includes>
246246
<include>**/*Spec.class</include>
247+
<include>**/*Test.class</include>
247248
</includes>
248249
</configuration>
249250
</plugin>

project-management-infrastructure/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
<artifactId>project-management-infrastructure</artifactId>
1414

1515
<properties>
16-
<maven.compiler.source>17</maven.compiler.source>
17-
<maven.compiler.target>17</maven.compiler.target>
16+
<maven.compiler.source>21</maven.compiler.source>
17+
<maven.compiler.target>21</maven.compiler.target>
1818
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1919
</properties>
2020
<dependencies>

project-management-infrastructure/src/main/java/life/qbic/projectmanagement/infrastructure/ontology/TIBTerminologyServiceIntegration.java

+147-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package life.qbic.projectmanagement.infrastructure.ontology;
22

3+
import static life.qbic.logging.service.LoggerFactory.logger;
4+
35
import com.fasterxml.jackson.core.JsonProcessingException;
46
import com.fasterxml.jackson.databind.DeserializationFeature;
57
import com.fasterxml.jackson.databind.JsonNode;
@@ -15,9 +17,14 @@
1517
import java.net.http.HttpResponse.BodyHandlers;
1618
import java.nio.charset.StandardCharsets;
1719
import java.time.Duration;
20+
import java.time.Instant;
1821
import java.util.ArrayList;
22+
import java.util.Comparator;
1923
import java.util.List;
24+
import java.util.Objects;
2025
import java.util.Optional;
26+
import java.util.stream.Collectors;
27+
import life.qbic.logging.api.Logger;
2128
import life.qbic.projectmanagement.application.ontology.LookupException;
2229
import life.qbic.projectmanagement.application.ontology.OntologyClass;
2330
import life.qbic.projectmanagement.application.ontology.TerminologySelect;
@@ -35,6 +42,7 @@
3542
@Service
3643
public class TIBTerminologyServiceIntegration implements TerminologySelect {
3744

45+
private static final Logger log = logger(TIBTerminologyServiceIntegration.class);
3846
private static final int TIMEOUT_5_SECONDS = 5;
3947
private static final HttpClient HTTP_CLIENT = httpClient(TIMEOUT_5_SECONDS);
4048

@@ -54,6 +62,7 @@ public class TIBTerminologyServiceIntegration implements TerminologySelect {
5462

5563
private final URI selectEndpointAbsoluteUrl;
5664
private final URI searchEndpointAbsoluteUrl;
65+
private final RequestCache cache;
5766

5867
@Autowired
5968
public TIBTerminologyServiceIntegration(
@@ -62,6 +71,7 @@ public TIBTerminologyServiceIntegration(
6271
@Value("${terminology.service.tib.api.url}") String tibApiUrl) {
6372
this.selectEndpointAbsoluteUrl = URI.create(tibApiUrl).resolve(selectEndpoint);
6473
this.searchEndpointAbsoluteUrl = URI.create(tibApiUrl).resolve(searchEndpoint);
74+
this.cache = new RequestCache(1000);
6575
}
6676

6777
/**
@@ -174,9 +184,13 @@ public List<OntologyClass> query(String searchTerm, int offset, int limit)
174184
@Override
175185
public Optional<OntologyClass> searchByCurie(String curie) throws LookupException {
176186
try {
177-
return searchByOboIdExact(curie).map(TIBTerminologyServiceIntegration::convert);
187+
return searchByOboIdExact(curie).map(this::updateCache)
188+
.map(TIBTerminologyServiceIntegration::convert);
178189
} catch (IOException e) {
179-
throw wrapIO(e);
190+
// this happens on network interrupts or if the remote service is down
191+
// we try to recover from the cache
192+
log.error("Error searching by CURIE: " + curie, e);
193+
return cache.findByCurie(curie).map(TIBTerminologyServiceIntegration::convert);
180194
} catch (InterruptedException e) {
181195
Thread.currentThread().interrupt();
182196
throw wrapInterrupted(e);
@@ -227,7 +241,7 @@ private List<TibTerm> fullSearch(String searchTerm, int offset, int limit)
227241
+ "&ontology=" + createOntologyFilterQueryParameter()))
228242
.header("Content-Type", "application/json").GET().build();
229243
var response = HTTP_CLIENT.send(termSelectQuery, BodyHandlers.ofString());
230-
return parseResponse(response);
244+
return parseResponse(response).stream().toList();
231245
}
232246

233247
/**
@@ -257,7 +271,7 @@ private List<TibTerm> select(String searchTerm, int offset, int limit)
257271
+ createOntologyFilterQueryParameter()))
258272
.header("Content-Type", "application/json").GET().build();
259273
var response = HTTP_CLIENT.send(termSelectQuery, BodyHandlers.ofString());
260-
return parseResponse(response);
274+
return parseResponse(response).stream().toList();
261275
}
262276

263277
/**
@@ -342,4 +356,133 @@ private List<TibTerm> parseResponse(HttpResponse<String> response) {
342356
throw wrapProcessingException(e);
343357
}
344358
}
359+
360+
// adds a term to the cache
361+
private TibTerm updateCache(TibTerm term) {
362+
cache.add(term);
363+
return term;
364+
}
365+
366+
/**
367+
* In-memory cache for {@link TibTerm} as failsafe for network interrupts.
368+
*
369+
* @since 1.9.0
370+
*/
371+
static class RequestCache {
372+
373+
// Pretty random, we need to see what value actual makes sense
374+
private static final int DEFAULT_CACHE_SIZE = 500;
375+
376+
private final List<TibTerm> cache = new ArrayList<>();
377+
private final int limit;
378+
private List<CacheEntryStat> accessFrequency = new ArrayList<>();
379+
380+
RequestCache() {
381+
limit = DEFAULT_CACHE_SIZE;
382+
}
383+
384+
RequestCache(int limit) {
385+
this.limit = limit;
386+
}
387+
388+
/**
389+
* Adds a {@link TibTerm} to the in-memory cache.
390+
* <p>
391+
* If the cache max size is reached, the oldest entry will be replaced with the one passed to
392+
* the function.
393+
*
394+
* @param term the term to store in the cache
395+
* @since 1.9.0
396+
*/
397+
void add(TibTerm term) {
398+
if (cache.contains(term)) {
399+
return;
400+
}
401+
if (cache.size() >= limit) {
402+
addByReplace(term);
403+
return;
404+
}
405+
cache.add(term);
406+
addStats(new CacheEntryStat(term));
407+
}
408+
409+
// Puts the term with the time of caching into an own list for tracking
410+
private void addStats(CacheEntryStat cacheEntryStat) {
411+
if (accessFrequency.contains(cacheEntryStat)) {
412+
return;
413+
}
414+
accessFrequency.add(cacheEntryStat);
415+
}
416+
417+
// A special case of adding by looking for the oldest cache entry and replacing it with
418+
// the provided one
419+
private void addByReplace(TibTerm term) {
420+
// We want to be sure that the access statistic list is in natural order
421+
ensureSorted();
422+
// We then remove the oldest cache entry
423+
if (!cache.isEmpty()) {
424+
cache.set(0, term);
425+
addStats(new CacheEntryStat(term));
426+
}
427+
}
428+
429+
// Ensures the natural order sorting by datetime, when the cache entry has been created
430+
// Oldest entry will be the first element, newest the last element of the list
431+
private void ensureSorted() {
432+
accessFrequency = accessFrequency.stream()
433+
.sorted(Comparator.comparing(CacheEntryStat::created, Instant::compareTo))
434+
.collect(Collectors.toList());
435+
}
436+
437+
/**
438+
* Searches for a matching {@link TibTerm} in the cache.
439+
*
440+
* @param curie the CURIE to search for
441+
* @return the search result, {@link Optional#empty()} if no match was found
442+
* @since 1.9.0
443+
*/
444+
Optional<TibTerm> findByCurie(String curie) {
445+
return cache.stream().filter(term -> term.oboId.equals(curie)).findFirst();
446+
}
447+
}
448+
449+
/**
450+
* A small container for when a cache entry has been created.
451+
*
452+
* @since 1.9.0
453+
*/
454+
static class CacheEntryStat {
455+
456+
private final TibTerm term;
457+
private final Instant created;
458+
459+
CacheEntryStat(TibTerm term) {
460+
this.term = term;
461+
created = Instant.now();
462+
}
463+
464+
/**
465+
* When the cache entry has been created
466+
*
467+
* @return the instant of creation
468+
* @since 1.9.0
469+
*/
470+
Instant created() {
471+
return created;
472+
}
473+
474+
@Override
475+
public boolean equals(Object o) {
476+
if (o == null || getClass() != o.getClass()) {
477+
return false;
478+
}
479+
CacheEntryStat that = (CacheEntryStat) o;
480+
return Objects.equals(term, that.term);
481+
}
482+
483+
@Override
484+
public int hashCode() {
485+
return Objects.hashCode(term);
486+
}
487+
}
345488
}

0 commit comments

Comments
 (0)