Skip to content

Commit 7a3c3f0

Browse files
committed
Merge remote-tracking branch 'origin/main'
# Conflicts: # ui/package.json
2 parents 23737c3 + c535371 commit 7a3c3f0

File tree

520 files changed

+48584
-14577
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

520 files changed

+48584
-14577
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
*.iml
12
.idea
23
.vscode
34
.java-version

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ The following sections are considered for each release: **Added, Changed, Fixed,
1111
- No updates yet.
1212

1313

14+
## [1.3.0] - 2025-09-22
15+
16+
1417
## [1.2.11] - 2025-09-03
1518

1619

api/pom.xml

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,8 @@
373373
</dependency>
374374
<dependency>
375375
<artifactId>wiremock-standalone</artifactId>
376-
<groupId>com.github.tomakehurst</groupId>
377-
<version>3.0.0</version>
376+
<groupId>org.wiremock</groupId>
377+
<version>3.0.3</version>
378378
</dependency>
379379
<dependency>
380380
<artifactId>postgresql</artifactId>
@@ -442,6 +442,11 @@
442442
<groupId>org.testcontainers</groupId>
443443
<scope>test</scope>
444444
</dependency>
445+
<dependency>
446+
<artifactId>rabbitmq</artifactId>
447+
<groupId>org.testcontainers</groupId>
448+
<scope>test</scope>
449+
</dependency>
445450
<dependency>
446451
<artifactId>jgrapht-core</artifactId>
447452
<groupId>org.jgrapht</groupId>
@@ -493,14 +498,23 @@
493498
</dependency>
494499
<dependency>
495500
<artifactId>hibernate-jcache</artifactId>
496-
<groupId>org.hibernate</groupId>
501+
<groupId>org.hibernate.orm</groupId>
497502
<version>${hibernate.version}</version>
498503
</dependency>
499504
<dependency>
500505
<artifactId>ehcache</artifactId>
501506
<groupId>org.ehcache</groupId>
502507
<version>3.10.8</version>
503508
</dependency>
509+
<dependency>
510+
<groupId>org.springframework</groupId>
511+
<artifactId>spring-web</artifactId>
512+
</dependency>
513+
<dependency>
514+
<groupId>software.amazon.awssdk</groupId>
515+
<artifactId>s3</artifactId>
516+
<version>2.33.0</version>
517+
</dependency>
504518
</dependencies>
505519
<description>Api for Lingo</description>
506520
<modelVersion>4.0.0</modelVersion>
@@ -510,24 +524,42 @@
510524
<parent>
511525
<artifactId>lingo</artifactId>
512526
<groupId>au.gov.digitalhealth</groupId>
513-
<version>1.2.12-SNAPSHOT</version>
527+
<version>1.3.1-SNAPSHOT</version>
514528
</parent>
515529
<profiles>
516530
<profile>
517531
<activation>
518-
<property>
519-
<name>buildnumber</name>
520-
</property>
532+
<activeByDefault>true</activeByDefault>
521533
</activation>
522534
<build>
523535
<plugins>
536+
<plugin>
537+
<artifactId>git-commit-id-maven-plugin</artifactId>
538+
<configuration>
539+
<generateGitPropertiesFile>true</generateGitPropertiesFile>
540+
<includeOnlyProperties>
541+
<includeOnlyProperty>git.commit.id.abbrev</includeOnlyProperty>
542+
</includeOnlyProperties>
543+
</configuration>
544+
<executions>
545+
<execution>
546+
<goals>
547+
<goal>revision</goal>
548+
</goals>
549+
<id>get-the-git-infos</id>
550+
<phase>initialize</phase>
551+
</execution>
552+
</executions>
553+
<groupId>io.github.git-commit-id</groupId>
554+
<version>5.0.0</version>
555+
</plugin>
524556
<plugin>
525557
<artifactId>maven-antrun-plugin</artifactId>
526558
<executions>
527559
<execution>
528560
<configuration>
529561
<target>
530-
<echo file="${staticdir}/buildnumber.txt">${buildnumber}</echo>
562+
<echo file="${staticdir}/buildnumber.txt">${buildnumber}-${git.commit.id.abbrev}</echo>
531563
</target>
532564
</configuration>
533565
<goals>
@@ -540,7 +572,7 @@
540572
</plugin>
541573
</plugins>
542574
</build>
543-
<id>azuredevops</id>
575+
<id>buildnumber</id>
544576
<properties>
545577
<staticdir>${project.build.directory}/classes/static</staticdir>
546578
</properties>
@@ -603,7 +635,8 @@
603635
<postgres.version>42.7.3</postgres.version>
604636
<problem-spring-web.version>0.23.0</problem-spring-web.version>
605637
<querydsl.version>5.1.0</querydsl.version>
606-
<snomed-owl-toolkit.version>5.4.0</snomed-owl-toolkit.version>
607638
<sentry.version>7.18.0</sentry.version>
639+
<snomed-owl-toolkit.version>5.4.0</snomed-owl-toolkit.version>
640+
<buildnumber>${project.version}</buildnumber>
608641
</properties>
609642
</project>

api/src/main/java/au/gov/digitalhealth/lingo/configuration/ApiWebConfiguration.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import au.gov.digitalhealth.lingo.auth.helper.AuthHelper;
1919
import au.gov.digitalhealth.lingo.log.SnowstormLogger;
2020
import au.gov.digitalhealth.lingo.util.AuthSnowstormLogger;
21+
import com.fasterxml.jackson.annotation.JsonInclude;
22+
import com.fasterxml.jackson.databind.ObjectMapper;
2123
import io.netty.handler.logging.LogLevel;
2224
import lombok.extern.java.Log;
2325
import org.springframework.beans.factory.annotation.Value;
@@ -26,7 +28,9 @@
2628
import org.springframework.http.HttpHeaders;
2729
import org.springframework.http.MediaType;
2830
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
31+
import org.springframework.http.codec.json.Jackson2JsonEncoder;
2932
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
33+
import org.springframework.web.reactive.function.client.ExchangeStrategies;
3034
import org.springframework.web.reactive.function.client.WebClient;
3135
import reactor.core.publisher.Mono;
3236
import reactor.netty.http.client.HttpClient;
@@ -53,10 +57,14 @@ public WebClient snowStormApiClient(
5357
"reactor.netty.http.client.HttpClient",
5458
LogLevel.DEBUG,
5559
AdvancedByteBufFormat.TEXTUAL);
60+
ObjectMapper customMapper =
61+
new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
62+
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder(customMapper, MediaType.APPLICATION_JSON);
5663
return webClientBuilder
5764
.codecs(
5865
clientCodecConfigurer ->
5966
clientCodecConfigurer.defaultCodecs().maxInMemorySize(1024 * 1024 * 100))
67+
.codecs(clientCodecConfigurer -> clientCodecConfigurer.customCodecs().register(encoder))
6068
.baseUrl(authoringServiceUrl)
6169
.clientConnector(new ReactorClientHttpConnector(httpClient))
6270
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
@@ -71,18 +79,30 @@ public WebClient authoringPlatformApiClient(
7179
return webClientBuilder
7280
.baseUrl(authoringServiceUrl)
7381
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
74-
.filter(authHelper.addImsAuthCookie) // Cookies are injected through filter
82+
.filter(authHelper.addImsAuthCookie)
83+
.exchangeStrategies(
84+
ExchangeStrategies.builder()
85+
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(10 * 1024 * 1024))
86+
.build())
7587
.build();
7688
}
7789

7890
@Bean
7991
public WebClient nameGeneratorApiClient(
8092
@Value("${name.generator.api.url}") String namegenApiUrl,
93+
@Value("${name.generator.api.key:}") String apiKeyHeader,
8194
WebClient.Builder webClientBuilder) {
82-
return webClientBuilder
83-
.baseUrl(namegenApiUrl)
84-
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
85-
.build();
95+
WebClient.Builder builder =
96+
webClientBuilder
97+
.baseUrl(namegenApiUrl)
98+
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
99+
100+
// Only add the API key header if it's not empty
101+
if (apiKeyHeader != null && !apiKeyHeader.isEmpty()) {
102+
builder.defaultHeader("X-API-Key", apiKeyHeader);
103+
}
104+
105+
return builder.build();
86106
}
87107

88108
@Bean
@@ -93,6 +113,10 @@ public WebClient defaultAuthoringPlatformApiClient(
93113
.baseUrl(authoringServiceUrl)
94114
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
95115
.filter(authHelper.addDefaultAuthCookie) // Cookies are injected through filter
116+
.exchangeStrategies(
117+
ExchangeStrategies.builder()
118+
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(10 * 1024 * 1024))
119+
.build())
96120
.build();
97121
}
98122

@@ -107,6 +131,16 @@ public WebClient sergioApiClient(
107131
.build();
108132
}
109133

134+
@Bean
135+
public WebClient fhirApiClient(
136+
@Value("${fhir.server.url}") String fhirServerUrl, WebClient.Builder webClientBuilder) {
137+
return webClientBuilder
138+
.baseUrl(fhirServerUrl)
139+
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
140+
.filter(logRequest())
141+
.build();
142+
}
143+
110144
private ExchangeFilterFunction logRequest() {
111145
return ExchangeFilterFunction.ofRequestProcessor(
112146
clientRequest -> {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2024 Australian Digital Health Agency ABN 84 425 496 912.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package au.gov.digitalhealth.lingo.configuration;
17+
18+
import java.util.concurrent.Executor;
19+
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
20+
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
21+
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.scheduling.annotation.AsyncConfigurer;
23+
import org.springframework.scheduling.annotation.EnableAsync;
24+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
25+
import org.springframework.security.core.Authentication;
26+
import org.springframework.security.core.context.SecurityContextHolder;
27+
import org.springframework.web.context.request.RequestAttributes;
28+
import org.springframework.web.context.request.RequestContextHolder;
29+
30+
@Configuration
31+
@EnableAsync
32+
public class AsyncConfig implements AsyncConfigurer {
33+
34+
@Override
35+
public Executor getAsyncExecutor() {
36+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
37+
executor.setCorePoolSize(10);
38+
executor.setMaxPoolSize(20);
39+
executor.setQueueCapacity(25);
40+
executor.setThreadNamePrefix("async-");
41+
42+
// This decorator preserves request context for all async tasks
43+
executor.setTaskDecorator(
44+
task -> {
45+
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
46+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
47+
48+
return () -> {
49+
RequestAttributes oldAttributes = RequestContextHolder.getRequestAttributes();
50+
Authentication oldAuthentication =
51+
SecurityContextHolder.getContext().getAuthentication();
52+
try {
53+
if (attributes != null) {
54+
RequestContextHolder.setRequestAttributes(attributes);
55+
}
56+
if (authentication != null) {
57+
SecurityContextHolder.getContext().setAuthentication(authentication);
58+
}
59+
task.run();
60+
} finally {
61+
RequestContextHolder.setRequestAttributes(oldAttributes);
62+
SecurityContextHolder.getContext().setAuthentication(oldAuthentication);
63+
}
64+
};
65+
});
66+
67+
executor.initialize();
68+
return executor;
69+
}
70+
71+
// Exception handler for async tasks
72+
@Override
73+
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
74+
return new SimpleAsyncUncaughtExceptionHandler();
75+
}
76+
}

0 commit comments

Comments
 (0)