Skip to content

Commit 9fecf0c

Browse files
authored
Merge pull request #876 from b2ihealthcare/feature/automatically-configure-dialect-aliases
feat: automatically configure known language dialect aliases after...
2 parents 05f75d2 + df134e0 commit 9fecf0c

File tree

6 files changed

+139
-28
lines changed

6 files changed

+139
-28
lines changed

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/BaseTerminologyResourceCreateRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ protected Builder completeResource(Builder builder) {
123123
.toolingId(toolingId)
124124
.extensionOf(extensionOf)
125125
.upgradeOf(upgradeOf)
126-
.settings(settings);
126+
.settings(settings == null ? Map.of() : settings);
127127
}
128128

129129
@Override

snomed/com.b2international.snowowl.snomed.common/src/com/b2international/snowowl/snomed/common/SnomedTerminologyComponentConstants.java

+32
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static com.google.common.base.Preconditions.checkState;
1919

20+
import java.util.Map;
2021
import java.util.regex.Matcher;
2122
import java.util.regex.Pattern;
2223

@@ -47,6 +48,37 @@ private SnomedTerminologyComponentConstants() {}
4748
public static final String SNOMED_URI_DEV = SNOMED_URI_BASE + "/xsct";
4849
public static final String SNOMED_URI_ID = SNOMED_URI_BASE + "/id";
4950

51+
// known language dialect aliases, see more information at: https://confluence.ihtsdotools.org/display/DOCECL/Appendix+C+-+Dialect+Aliases
52+
public static final Map<String, String> LANG_REFSET_DIALECT_ALIASES = Map.ofEntries(
53+
Map.entry("554461000005103", "da-dk"),
54+
Map.entry("32570271000036106", "en-au"),
55+
Map.entry("19491000087109", "en-ca"),
56+
Map.entry("900000000000508004", "en-gb"),
57+
Map.entry("21000220103", "en-ie"),
58+
Map.entry("271000210107", "en-nz"),
59+
Map.entry("900000000000509007", "en-us"),
60+
Map.entry("608771002", "en-int-gmdn"),
61+
Map.entry("999001261000000100", "en-nhs-clinical"),
62+
Map.entry("999000671000001103", "en-nhs-dmd"),
63+
Map.entry("999000691000001104", "en-nhs-pharmacy"),
64+
Map.entry("999000681000001101", "en-uk-drug"),
65+
Map.entry("999001251000000103", "en-uk-ext"),
66+
Map.entry("448879004", "es"),
67+
Map.entry("450828004", "es-ar"),
68+
Map.entry("5641000179103", "es-uy"),
69+
Map.entry("71000181105", "et-ee"),
70+
Map.entry("722130004", "dr"),
71+
Map.entry("722131000", "fr"),
72+
Map.entry("21000172104", "fr-be"),
73+
Map.entry("20581000087109", "fr-ca"),
74+
Map.entry("722129009", "ja"),
75+
Map.entry("31000172101", "nl-be"),
76+
Map.entry("31000146106", "nl-nl"),
77+
Map.entry("61000202103", "nb-no"),
78+
Map.entry("91000202106", "nn-no"),
79+
Map.entry("46011000052107", "sv-se"),
80+
Map.entry("722128001", "zh")
81+
);
5082

5183
public static String getNamespace(String conceptId, String fsn) {
5284
return getNamespace(DEFAULT_NAMESPACE_PATTERN, conceptId, fsn);

snomed/com.b2international.snowowl.snomed.core.rest.tests/src/com/b2international/snowowl/snomed/core/rest/SnomedRf2ContentImportTest.java

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 B2i Healthcare Pte Ltd, http://b2i.sg
2+
* Copyright 2020-2021 B2i Healthcare Pte Ltd, http://b2i.sg
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
1515
*/
1616
package com.b2international.snowowl.snomed.core.rest;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.junit.Assert.assertNotNull;
1920
import static org.junit.Assert.assertTrue;
2021

@@ -26,15 +27,20 @@
2627
import java.text.SimpleDateFormat;
2728
import java.util.*;
2829
import java.util.Map.Entry;
30+
import java.util.concurrent.TimeUnit;
2931
import java.util.stream.Stream;
3032

3133
import org.junit.AfterClass;
3234
import org.junit.BeforeClass;
3335
import org.junit.Test;
3436

37+
import com.b2international.snowowl.core.codesystem.CodeSystemRequests;
3538
import com.b2international.snowowl.core.util.PlatformUtil;
39+
import com.b2international.snowowl.snomed.common.SnomedConstants.Concepts;
40+
import com.b2international.snowowl.snomed.common.SnomedTerminologyComponentConstants;
3641
import com.b2international.snowowl.snomed.core.domain.Rf2ReleaseType;
3742
import com.b2international.snowowl.test.commons.Resources;
43+
import com.b2international.snowowl.test.commons.SnomedContentRule;
3844
import com.google.common.base.Splitter;
3945
import com.google.common.collect.HashMultimap;
4046
import com.google.common.collect.ImmutableMap;
@@ -108,6 +114,32 @@ public void verifyDeltaContent() throws Exception {
108114

109115
assertRf2Equals(getDeltaLines(originalLines, effectiveTime, effectiveTime), getLines(result));
110116
}
117+
118+
@Test
119+
public void verifyAutomaticDialectConfiguration() throws Exception {
120+
final Map<String, Object> settings = CodeSystemRequests.prepareGetCodeSystem(SnomedContentRule.SNOMEDCT_ID)
121+
.buildAsync()
122+
.execute(getBus())
123+
.getSync(1, TimeUnit.MINUTES)
124+
.getSettings();
125+
assertThat(settings)
126+
.containsEntry(SnomedTerminologyComponentConstants.CODESYSTEM_LANGUAGE_CONFIG_KEY, List.of(
127+
// this entry is pre-configured, should be kept after import
128+
Map.of(
129+
"languageTag", "en",
130+
"languageRefSetIds", List.of(Concepts.REFSET_LANGUAGE_TYPE_UK, Concepts.REFSET_LANGUAGE_TYPE_US)
131+
),
132+
// these two entries come from the default dialect configuration map, should be appended
133+
Map.of(
134+
"languageTag", "en-gb",
135+
"languageRefSetIds", List.of(Concepts.REFSET_LANGUAGE_TYPE_UK)
136+
),
137+
Map.of(
138+
"languageTag", "en-us",
139+
"languageRefSetIds", List.of(Concepts.REFSET_LANGUAGE_TYPE_US)
140+
)
141+
));
142+
}
111143

112144
private void assertRf2Equals(final Multimap<String, String> expected, final Multimap<String, String> result) {
113145

snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/datastore/SnomedDescriptionUtils.java

+30-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.util.*;
1010
import java.util.Map.Entry;
11+
import java.util.stream.Collectors;
1112

1213
import com.b2international.commons.CompareUtils;
1314
import com.b2international.commons.ExplicitFirstOrdering;
@@ -138,17 +139,39 @@ public static List<String> getLanguageRefSetIds(final BranchContext context, fin
138139
return languageRefSetIds;
139140
}
140141

142+
/**
143+
* Returns the currently configured dialect aliast configuration from the given context. If there is no such setting configured it returns an empty {@link ListMultimap}.
144+
* @param context
145+
* @return a {@link ListMultimap} that has all the configured dialect aliases, never <code>null</code>
146+
*/
141147
public static ListMultimap<String,String> getLanguageMapping(final BranchContext context) {
142-
List<Map<String, Object>> languageMapping = (List<Map<String, Object>>) context.service(TerminologyResource.class).getSettings().getOrDefault(SnomedTerminologyComponentConstants.CODESYSTEM_LANGUAGE_CONFIG_KEY, List.of());
148+
return getLanguageMapping(context.service(ObjectMapper.class), context.service(TerminologyResource.class));
149+
}
150+
151+
/**
152+
* Returns the currently configured dialect aliast configuration from the given {@link TerminologyResource}'s settings. If there is no such setting configured it returns an empty {@link ListMultimap}.
153+
* @param mapper
154+
* @param resource
155+
* @return a {@link ListMultimap} that has all the configured dialect aliases, never <code>null</code>
156+
*/
157+
public static ListMultimap<String, String> getLanguageMapping(final ObjectMapper mapper, final TerminologyResource resource) {
143158
ListMultimap<String, String> languageMap = ArrayListMultimap.create();
144-
ObjectMapper mapper = context.service(ObjectMapper.class);
145-
languageMapping.forEach(mapping -> {
146-
SnomedLanguageConfig snomedLanguageConfig = mapper.convertValue(mapping, SnomedLanguageConfig.class);
147-
languageMap.putAll(snomedLanguageConfig.getLanguageTag(), snomedLanguageConfig.getLanguageRefSetIds());
148-
});
149-
159+
getLanguagesConfiguration(mapper, resource).forEach(mapping -> languageMap.putAll(mapping.getLanguageTag(), mapping.getLanguageRefSetIds()));
150160
return languageMap;
151161
}
162+
163+
/**
164+
* Returns the currently configured language settings from the given {@link TerminologyResource}'s settings. If there is no such setting configured it returns an empty {@link List}.
165+
* @param mapper
166+
* @param resource
167+
* @return a {@link List} that has all the configured language settings, never <code>null</code>
168+
*/
169+
public static List<SnomedLanguageConfig> getLanguagesConfiguration(final ObjectMapper mapper, final TerminologyResource resource) {
170+
return ((List<Map<String, Object>>) resource.getSettings().getOrDefault(SnomedTerminologyComponentConstants.CODESYSTEM_LANGUAGE_CONFIG_KEY, List.of()))
171+
.stream()
172+
.map(config -> mapper.convertValue(config, SnomedLanguageConfig.class))
173+
.collect(Collectors.toList());
174+
}
152175

153176
private SnomedDescriptionUtils() {}
154177

snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/datastore/request/rf2/SnomedRf2ImportRequest.java

+43-11
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@
6363
import com.b2international.snowowl.core.request.io.ImportResponse;
6464
import com.b2international.snowowl.core.uri.ComponentURI;
6565
import com.b2international.snowowl.eventbus.IEventBus;
66+
import com.b2international.snowowl.snomed.common.SnomedTerminologyComponentConstants;
6667
import com.b2international.snowowl.snomed.core.domain.Rf2ReleaseType;
6768
import com.b2international.snowowl.snomed.core.domain.refset.SnomedRefSetType;
69+
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSet;
70+
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSets;
71+
import com.b2international.snowowl.snomed.datastore.SnomedDescriptionUtils;
72+
import com.b2international.snowowl.snomed.datastore.config.SnomedLanguageConfig;
6873
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedConceptDocument;
6974
import com.b2international.snowowl.snomed.datastore.request.SnomedRequests;
7075
import com.b2international.snowowl.snomed.datastore.request.rf2.importer.*;
@@ -73,13 +78,15 @@
7378
import com.fasterxml.jackson.annotation.JsonProperty;
7479
import com.fasterxml.jackson.core.JsonProcessingException;
7580
import com.fasterxml.jackson.databind.MappingIterator;
81+
import com.fasterxml.jackson.databind.ObjectMapper;
7682
import com.fasterxml.jackson.databind.ObjectReader;
7783
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
7884
import com.fasterxml.jackson.dataformat.csv.CsvParser;
7985
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
8086
import com.google.common.base.Stopwatch;
8187
import com.google.common.base.Strings;
8288
import com.google.common.collect.ImmutableSet;
89+
import com.google.common.collect.Maps;
8390

8491
/**
8592
* @since 6.0.0
@@ -220,7 +227,7 @@ ImportResponse doImport(final BranchContext context, final File rf2Archive, fina
220227
}
221228

222229
// Update locales registered on the code system
223-
updateLocales(context, codeSystemUri);
230+
updateCodeSystemSettings(context, codeSystemUri);
224231
}
225232

226233
return ImportResponse.success(visitedComponents.build(), reporter.getDefects());
@@ -353,27 +360,52 @@ private DB createDb() {
353360
}
354361
}
355362

356-
private void updateLocales(final BranchContext context, final ResourceURI codeSystemUri) throws Exception {
357-
/*
358-
* XXX: The default language in locales is always "en", as there is no
359-
* machine-readable information about what language code each language type
360-
* reference set is associated with.
361-
*/
362-
final List<ExtendedLocale> locales = SnomedRequests.prepareSearchRefSet()
363+
private void updateCodeSystemSettings(final BranchContext context, final ResourceURI codeSystemUri) throws Exception {
364+
SnomedReferenceSets languageReferenceSets = SnomedRequests.prepareSearchRefSet()
363365
.all()
364366
.filterByType(SnomedRefSetType.LANGUAGE)
365367
.filterByActive(true)
366368
.setFields(SnomedConceptDocument.Fields.ID)
367369
.sortBy(SortField.ascending(SnomedConceptDocument.Fields.ID))
368370
.build()
369-
.execute(context)
371+
.execute(context);
372+
373+
/*
374+
* XXX: The default language in locales is always "en", as there is no
375+
* machine-readable information about what language code each language type
376+
* reference set is associated with.
377+
*/
378+
final List<ExtendedLocale> locales = languageReferenceSets
370379
.stream()
371380
.map(refSet -> new ExtendedLocale("en", "", refSet.getId()))
372381
.collect(Collectors.toList());
373382

383+
// fetch codesystem again to get the latest settings
384+
CodeSystem currentSnomedCodeSystem = CodeSystemRequests.prepareGetCodeSystem(codeSystemUri.getResourceId())
385+
.buildAsync()
386+
.get(context);
387+
388+
Map<String, SnomedLanguageConfig> mergedLanguagesConfiguration = Maps.newLinkedHashMap();
389+
SnomedDescriptionUtils.getLanguagesConfiguration(context.service(ObjectMapper.class), currentSnomedCodeSystem).forEach(config -> {
390+
mergedLanguagesConfiguration.put(config.getLanguageTag(), config);
391+
});
392+
393+
languageReferenceSets.stream()
394+
.map(SnomedReferenceSet::getId)
395+
.filter(SnomedTerminologyComponentConstants.LANG_REFSET_DIALECT_ALIASES::containsKey)
396+
.forEach(langRefsetId -> {
397+
final String dialect = SnomedTerminologyComponentConstants.LANG_REFSET_DIALECT_ALIASES.get(langRefsetId);
398+
// ignore any aliases that are already defined by using computeIfAbsent
399+
mergedLanguagesConfiguration.computeIfAbsent(dialect, languageTag -> new SnomedLanguageConfig(languageTag, langRefsetId));
400+
401+
});
402+
374403
CodeSystemRequests.prepareUpdateCodeSystem(codeSystemUri.getResourceId())
375-
.setSettings(Map.of(CodeSystem.CommonSettings.LOCALES, locales))
376-
.build(context.service(User.class).getUsername(), "Update available list of locales on " + codeSystemUri.getResourceId())
404+
.setSettings(Map.of(
405+
CodeSystem.CommonSettings.LOCALES, locales,
406+
SnomedTerminologyComponentConstants.CODESYSTEM_LANGUAGE_CONFIG_KEY, mergedLanguagesConfiguration.values()
407+
))
408+
.build(context.service(User.class).getUsername(), String.format("Update '%s' settings based on RF2 import", codeSystemUri.getResourceId()))
377409
.execute(context.service(IEventBus.class))
378410
.getSync(2, TimeUnit.MINUTES);
379411
}

tests/com.b2international.snowowl.test.commons/src/com/b2international/snowowl/test/commons/SnomedContentRule.java

-8
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,6 @@ private void createCodeSystemIfNotExist() {
135135
Map.of(
136136
"languageTag", "en",
137137
"languageRefSetIds", Lists.newArrayList(Concepts.REFSET_LANGUAGE_TYPE_UK, Concepts.REFSET_LANGUAGE_TYPE_US)
138-
),
139-
Map.of(
140-
"languageTag", "en-us",
141-
"languageRefSetIds", Lists.newArrayList(Concepts.REFSET_LANGUAGE_TYPE_US)
142-
),
143-
Map.of(
144-
"languageTag", "en-gb",
145-
"languageRefSetIds", Lists.newArrayList(Concepts.REFSET_LANGUAGE_TYPE_UK)
146138
)
147139
)
148140
))

0 commit comments

Comments
 (0)