Skip to content

Commit 97bf0f7

Browse files
authored
Merge pull request #603 from ansforge/feat/dispatcher/migrate-to-client-config-map
[ Dispatcher] Refacto : migration des maps de configuration vers un objet de configuration client
2 parents f724699 + 9744c6b commit 97bf0f7

32 files changed

Lines changed: 631 additions & 618 deletions

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ 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";

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();

hub/dispatcher/src/main/java/com/hubsante/hub/service/ClientPropertiesRegistry.java

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@
1515
*/
1616
package com.hubsante.hub.service;
1717

18+
import static com.hubsante.hub.config.Constants.DEFAULT_DIRECT_CISU_PREFERENCE;
19+
import static com.hubsante.hub.config.Constants.UNKNOWN;
20+
21+
import com.hubsante.hub.config.LogConstants;
22+
import com.hubsante.hub.config.StructuredLogger;
1823
import com.hubsante.hub.exception.ClientConfigurationException;
1924
import com.hubsante.hub.model.ClientProperties;
2025
import com.hubsante.hub.model.PerimeterDefinition;
2126
import java.util.*;
2227
import java.util.function.Function;
2328
import java.util.stream.Collectors;
29+
import lombok.extern.slf4j.Slf4j;
2430
import org.springframework.beans.factory.annotation.Value;
2531
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
2632
import org.springframework.boot.context.properties.bind.Bindable;
@@ -31,15 +37,17 @@
3137
import org.springframework.stereotype.Component;
3238

3339
@Component
40+
@Slf4j
3441
public class ClientPropertiesRegistry {
42+
private static final StructuredLogger structuredLog = new StructuredLogger(log);
43+
3544
private Map<String, ClientProperties> clientsById = Map.of();
3645

37-
public ClientPropertiesRegistry(@Value("${client.configuration.file}") Resource resource)
38-
throws Exception {
46+
public ClientPropertiesRegistry(@Value("${client.configuration.file}") Resource resource) {
3947
load(resource);
4048
}
4149

42-
private void load(Resource resource) throws Exception {
50+
private void load(Resource resource) {
4351
try {
4452
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
4553
factory.setResources(resource);
@@ -135,12 +143,63 @@ private ClientConfigurationException buildException(Map<String, List<String>> er
135143
}
136144

137145
public ClientProperties get(String clientId) {
138-
ClientProperties clientProperties = clientsById.get(clientId);
146+
return clientsById.get(clientId);
147+
}
148+
149+
public String[] getClientVersionsForPerimeter(String clientId, String perimeterName) {
150+
ClientProperties clientProperties = get(clientId);
151+
152+
if (clientProperties == null) {
153+
structuredLog.warn(
154+
"Client has no configuration", Map.of(LogConstants.RECIPIENT_ID, clientId));
155+
return null;
156+
}
157+
158+
PerimeterDefinition perimeter =
159+
clientProperties.perimeters().stream()
160+
.filter(p -> p.name().equals(perimeterName))
161+
.findFirst()
162+
.orElse(null);
163+
164+
if (perimeter == null) {
165+
structuredLog.warn(
166+
"Client does not support perimeter " + perimeterName,
167+
Map.of(LogConstants.RECIPIENT_ID, clientId));
168+
return null;
169+
}
170+
return perimeter.versions().toArray(String[]::new);
171+
}
139172

173+
public Boolean isClientUseXml(String clientId) {
174+
ClientProperties clientProperties = get(clientId);
175+
176+
if (clientProperties == null) {
177+
return null;
178+
}
179+
return clientProperties.useXml();
180+
}
181+
182+
public boolean isClientDirectCisu(String clientId) {
183+
ClientProperties clientProperties = get(clientId);
184+
185+
return clientProperties != null
186+
? clientProperties.directCisu()
187+
: DEFAULT_DIRECT_CISU_PREFERENCE;
188+
}
189+
190+
public List<String> getClientInhibitedUseCases(String clientId) {
191+
ClientProperties clientProperties = get(clientId);
140192
if (clientProperties == null) {
141-
throw new ClientConfigurationException("client " + clientId + " is not configured");
193+
return new ArrayList<>();
142194
}
195+
return clientProperties.inhibitedUseCases();
196+
}
197+
198+
public String getClientEditor(String clientId) {
199+
ClientProperties clientProperties = get(clientId);
143200

144-
return clientProperties;
201+
if (clientProperties != null && clientProperties.editor() != null) {
202+
return clientProperties.editor();
203+
} else return UNKNOWN;
145204
}
146205
}

0 commit comments

Comments
 (0)