Skip to content

Commit b5713ab

Browse files
authored
Merge pull request #613 from ansforge/feat/dispatcher/clients-conf-refacto
[ Dispatcher ] refacto du chargement de la config client
2 parents 337eec5 + 5dd0370 commit b5713ab

46 files changed

Lines changed: 1237 additions & 608 deletions

Some content is hidden

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

hub/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ out/
2727
!**/src/test/**/out/
2828
**/application-bbo.properties
2929
**/client.preferences.csv
30+
**/src/main/resources/clients.yaml
3031
dispatcher/gradle.properties
3132

3233
### NetBeans ###

hub/dispatcher/src/main/java/com/hubsante/hub/config/Constants.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,16 @@ public class Constants {
3434
public static final String DISPATCHED_MESSAGE = "dispatch.message";
3535
public static final String USE_CASE_TAG = "use_case";
3636
public static final String UNKNOWN = "unknown";
37+
public static final boolean DEFAULT_DIRECT_CISU_PREFERENCE = false;
3738
public static final String FR_HEALTH_PREFIX = "fr.health";
3839
public static final String FR_FIRE_PREFIX = "fr.fire";
3940
public static final String FR_CISU_PREFIX = "fr.cisu";
40-
public static final String NEXSIS_VHOST = "15-nexsis_v1.9";
4141
public static final String HEALTH_VHOST_PREFIX = "15-15_v";
42+
public static final String NEXSIS_HUBEX_PARTNER = "fire";
4243
public static final Map<String, String> HUBEX_PERIMETER_PREFIXES =
4344
Map.of(
4445
"15-15", "fr.health",
4546
"15-nexsis", "fr.fire");
46-
public static final Map<String, String> CONVERSION_VHOST_MODEL =
47-
Map.of(
48-
"15-15_v1.5", "v1",
49-
"15-15_v2.0", "v2",
50-
"15-15_v2.1", "v3",
51-
"15-nexsis_v1.9", "v3");
5247

5348
public enum Perimeter {
5449
HEALTH("15-15"),

hub/dispatcher/src/main/java/com/hubsante/hub/config/HubConfiguration.java

Lines changed: 13 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,17 @@
1515
*/
1616
package com.hubsante.hub.config;
1717

18+
import com.hubsante.hub.service.ClientPropertiesRegistry;
1819
import com.hubsante.model.EdxlHandler;
1920
import com.hubsante.model.Validator;
20-
import com.univocity.parsers.common.ParsingContext;
21-
import com.univocity.parsers.common.processor.ObjectRowProcessor;
22-
import com.univocity.parsers.csv.CsvParser;
23-
import com.univocity.parsers.csv.CsvParserSettings;
2421
import io.micrometer.core.aop.TimedAspect;
2522
import io.micrometer.core.instrument.MeterRegistry;
2623
import jakarta.annotation.PostConstruct;
2724
import java.io.*;
2825
import java.nio.charset.StandardCharsets;
29-
import java.nio.file.Files;
3026
import java.util.*;
31-
import java.util.stream.Collectors;
3227
import lombok.extern.slf4j.Slf4j;
33-
import org.apache.commons.csv.CSVFormat;
34-
import org.apache.commons.csv.CSVParser;
35-
import org.apache.commons.csv.CSVRecord;
28+
import org.springframework.beans.factory.annotation.Autowired;
3629
import org.springframework.beans.factory.annotation.Value;
3730
import org.springframework.context.annotation.Bean;
3831
import org.springframework.context.annotation.Configuration;
@@ -42,16 +35,8 @@
4235
@Configuration
4336
public class HubConfiguration {
4437

45-
private static final int ROW_LENGTH = 11;
4638
private static final String DATA_DIVIDER = ",";
4739
private static final String COLUMN_DIVIDER = ";";
48-
private static final String CLIENT_ID_HEADER = "client_id";
49-
private static final String INHIBITED_USE_CASES_HEADER = "inhibited_use_cases";
50-
51-
private static final StructuredLogger structuredLog = new StructuredLogger(log);
52-
53-
@Value("${client.preferences.file}")
54-
private File configFile;
5540

5641
@Value("${supported.messages.file}")
5742
private File supportedMessagesFile;
@@ -64,110 +49,19 @@ public class HubConfiguration {
6449
@Value("${spring.rabbitmq.virtual-host}")
6550
private String vhost;
6651

67-
private HashMap<String, Boolean> useXmlPreferences = new HashMap<>();
68-
private HashMap<String, Boolean> directCisuPreferences = new HashMap<>();
69-
private HashMap<String, String> clientsEditorMap = new HashMap<>();
70-
private Map<String, Map<String, String>> clientsPerimeterAndVersions = new HashMap<>();
71-
private Map<String, List<String>> clientsInhibitedMessages = new HashMap<>();
52+
@Autowired private ClientPropertiesRegistry clientPropertiesRegistry;
53+
7254
private List<String> supportedMessages;
7355

7456
@PostConstruct
7557
public void init() throws Exception {
58+
// We first get the parameterized default message TTL
59+
defaultTTL = Long.parseLong(this.ttlProperty);
7660

77-
try {
78-
// We first get the parameterized default message TTL
79-
defaultTTL = Long.parseLong(this.ttlProperty);
80-
81-
// We explicitly set the Locale to ensure cross platform consistency
82-
Locale.setDefault(Locale.ENGLISH);
83-
84-
// We define a custom row processor to read the config file
85-
// we override the rowProcessed method on the fly to store the config in a HashMap
86-
// then we define the parser settings and parse the file
87-
ObjectRowProcessor clientPreferencesRowProcessor =
88-
new ObjectRowProcessor() {
89-
@Override
90-
public void rowProcessed(Object[] objects, ParsingContext parsingContext) {
91-
if (objects.length != ROW_LENGTH) {
92-
log.warn(
93-
"There were more than {} columns in the client preferences file, extra columns are being ignored",
94-
ROW_LENGTH);
95-
}
96-
String[] items = Arrays.asList(objects).toArray(new String[ROW_LENGTH]);
97-
useXmlPreferences.put(items[0], Boolean.parseBoolean(items[1]));
98-
directCisuPreferences.put(items[0], Boolean.parseBoolean(items[2]));
99-
clientsEditorMap.put(items[0], items[3]);
100-
}
101-
};
102-
CsvParserSettings parserSettings = new CsvParserSettings();
103-
parserSettings.getFormat().setLineSeparator("\n");
104-
parserSettings.getFormat().setDelimiter(';');
105-
parserSettings.setHeaderExtractionEnabled(true);
106-
parserSettings.setNullValue("");
107-
parserSettings.setProcessor(clientPreferencesRowProcessor);
108-
109-
CsvParser parser = new CsvParser(parserSettings);
110-
parser.parse(new BufferedReader(new FileReader(configFile, StandardCharsets.UTF_8)));
111-
clientsPerimeterAndVersions = loadClientsPerimetersAndVersions();
112-
clientsInhibitedMessages = loadClientsInhibitedMessages();
113-
supportedMessages = loadSupportedMessages(vhost);
114-
} catch (Exception e) {
115-
throw new Exception("Could not read config file " + configFile.getAbsolutePath(), e);
116-
}
117-
}
118-
119-
public Map<String, Map<String, String>> loadClientsPerimetersAndVersions() throws IOException {
120-
Map<String, Map<String, String>> clientsPerimeterAndVersions = new HashMap<>();
121-
BufferedReader reader =
122-
new BufferedReader(new FileReader(configFile, StandardCharsets.UTF_8));
123-
String headerLine = reader.readLine();
124-
String[] headers = headerLine.split(COLUMN_DIVIDER);
125-
int numberOfColumns = headers.length;
126-
127-
Set<String> perimeterNames =
128-
Arrays.stream(Constants.Perimeter.values())
129-
.map(Constants.Perimeter::getName)
130-
.collect(Collectors.toSet());
131-
132-
Map<String, Integer> perimeterColumnIndexes = new HashMap<>();
133-
for (int i = 0; i < numberOfColumns; i++) {
134-
if (perimeterNames.contains(headers[i])) {
135-
perimeterColumnIndexes.put(headers[i], i);
136-
}
137-
}
138-
String line;
139-
while ((line = reader.readLine()) != null) {
140-
String[] values = line.split(COLUMN_DIVIDER, -1); // -1 allows trailing empty strings
141-
142-
if (values.length < numberOfColumns) continue;
143-
144-
String clientId = values[0];
145-
Map<String, String> allPerimetersVersions = new HashMap<>();
146-
147-
for (Map.Entry<String, Integer> perimeterMatch : perimeterColumnIndexes.entrySet()) {
148-
String perimeterName = perimeterMatch.getKey();
149-
int columnIndex = perimeterMatch.getValue();
150-
allPerimetersVersions.put(perimeterName, values[columnIndex]);
151-
}
152-
153-
clientsPerimeterAndVersions.put(clientId, allPerimetersVersions);
154-
}
155-
156-
reader.close();
157-
return clientsPerimeterAndVersions;
158-
}
61+
// We explicitly set the Locale to ensure cross platform consistency
62+
Locale.setDefault(Locale.ENGLISH);
15963

160-
public String[] getClientVersionsForPerimeter(String clientId, String perimeterName) {
161-
Map<String, String> clientPerimeterDefinition =
162-
clientsPerimeterAndVersions.getOrDefault(clientId, null);
163-
if (clientPerimeterDefinition == null) {
164-
structuredLog.warn(
165-
"ClientId was not found in clientsPerimeterAndVersions, or the variable is not initialized.",
166-
Map.of(LogConstants.RECIPIENT_ID, clientId));
167-
return null;
168-
}
169-
String versions = clientPerimeterDefinition.getOrDefault(perimeterName, null);
170-
return splitString(versions);
64+
supportedMessages = loadSupportedMessages(vhost);
17165
}
17266

17367
public List<String> loadSupportedMessages(String vhost) throws Exception {
@@ -198,64 +92,10 @@ public List<String> loadSupportedMessages(String vhost) throws Exception {
19892
return supportedMessages;
19993
}
20094

201-
private Map<String, List<String>> loadClientsInhibitedMessages() throws IOException {
202-
Map<String, List<String>> result = new HashMap<>();
203-
204-
try (Reader reader = Files.newBufferedReader(configFile.toPath());
205-
CSVParser parser =
206-
CSVFormat.DEFAULT
207-
.builder()
208-
.setDelimiter(';')
209-
.setHeader()
210-
.setSkipHeaderRecord(true)
211-
.setTrim(true)
212-
.build()
213-
.parse(reader)) {
214-
boolean hasUseCasesColumn =
215-
parser.getHeaderMap().containsKey(INHIBITED_USE_CASES_HEADER);
216-
217-
for (CSVRecord record : parser) {
218-
219-
String clientId = record.get(CLIENT_ID_HEADER);
220-
List<String> useCases;
221-
222-
if (hasUseCasesColumn) {
223-
useCases =
224-
Arrays.stream(record.get(INHIBITED_USE_CASES_HEADER).split(","))
225-
.map(String::trim)
226-
.filter(s -> !s.isEmpty())
227-
.toList();
228-
} else {
229-
useCases = List.of();
230-
}
231-
232-
result.put(clientId, useCases);
233-
}
234-
}
235-
236-
return Collections.unmodifiableMap(result);
237-
}
238-
23995
public List<String> getSupportedMessages() {
24096
return supportedMessages;
24197
}
24298

243-
public HashMap<String, Boolean> getUseXmlPreferences() {
244-
return useXmlPreferences;
245-
}
246-
247-
public HashMap<String, Boolean> getDirectCisuPreferences() {
248-
return directCisuPreferences;
249-
}
250-
251-
public HashMap<String, String> getClientsEditorMap() {
252-
return clientsEditorMap;
253-
}
254-
255-
public Map<String, List<String>> getClientsInhibitedMessages() {
256-
return clientsInhibitedMessages;
257-
}
258-
25999
public long getDefaultTTL() {
260100
return defaultTTL;
261101
}
@@ -264,6 +104,10 @@ public String getVhost() {
264104
return vhost;
265105
}
266106

107+
public ClientPropertiesRegistry getClientPropertiesRegistry() {
108+
return clientPropertiesRegistry;
109+
}
110+
267111
@Bean
268112
public EdxlHandler edxlHandler() {
269113
return new EdxlHandler();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright © 2023-2026 Agence du Numerique en Sante (ANS)
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 com.hubsante.hub.exception;
17+
18+
public class ClientConfigurationException extends RuntimeException {
19+
20+
public ClientConfigurationException(String message) {
21+
super(message);
22+
}
23+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright © 2023-2026 Agence du Numerique en Sante (ANS)
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 com.hubsante.hub.model;
17+
18+
import java.util.List;
19+
20+
public record ClientProperties(
21+
String clientId,
22+
boolean useXml,
23+
boolean directCisu,
24+
String editor,
25+
List<PerimeterDefinition> perimeters,
26+
List<String> inhibitedUseCases) {
27+
28+
public ClientProperties {
29+
inhibitedUseCases = inhibitedUseCases == null ? List.of() : List.copyOf(inhibitedUseCases);
30+
}
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright © 2023-2026 Agence du Numerique en Sante (ANS)
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 com.hubsante.hub.model;
17+
18+
import java.util.List;
19+
20+
public record PerimeterDefinition(String name, List<String> versions) {}

0 commit comments

Comments
 (0)