4444import org .folio .querytool .domain .dto .ValueSourceApi ;
4545import org .folio .querytool .domain .dto .ValueWithLabel ;
4646import org .folio .spring .FolioExecutionContext ;
47+ import org .folio .spring .i18n .service .TranslationService ;
4748import org .springframework .lang .Nullable ;
4849import org .springframework .stereotype .Service ;
4950
@@ -86,6 +87,8 @@ public class EntityTypeService {
8687 "XBC" , "XBD" , "FIM" , "FRF" , "XFO" , "XFU" , "GHC" , "DEM" , "XAU" , "GRD" , "GWP" , "IEP" , "ITL" , "LVL" , "LTL" , "LUF" , "MGF" , "MTL" , "MRO" , "MXV" ,
8788 "MZM" , "XPD" , "PHP" , "XPT" , "PTE" , "ROL" , "RUR" , "CSD" , "SLE" , "SLL" , "XAG" , "SKK" , "SIT" , "ESP" , "XDR" , "XSU" , "SDD" , "SRG" , "STD" , "XTS" ,
8889 "TPE" , "TRL" , "TMM" , "USN" , "USS" , "XXX" , "UYI" , "VEB" , "VEF" , "VED" , "CHE" , "CHW" , "YUM" , "ZWN" , "ZMK" , "ZWD" , "ZWR" );
90+ private static final String COUNTRIES_FILEPATH = "country_codes.json" ;
91+ private static final String COUNTRY_TRANSLATION_TEMPLATE = "mod-fqm-manager.countries.%s" ;
8992
9093 private final EntityTypeRepository entityTypeRepository ;
9194 private final EntityTypeFlatteningService entityTypeFlatteningService ;
@@ -99,6 +102,7 @@ public class EntityTypeService {
99102 private final FolioExecutionContext folioExecutionContext ;
100103 private final ClockService clockService ;
101104 private final SimpleHttpClient simpleHttpClient ;
105+ private final TranslationService translationService ;
102106
103107 /**
104108 * Returns the list of all entity types.
@@ -211,11 +215,14 @@ public ColumnValues getFieldValues(UUID entityTypeId, String fieldName, @Nullabl
211215 // entity types using this MUST declare a dependency on view `_mod_search_languages_availability_indicator`
212216 // to ensure that this source is available
213217 case "languages" -> getLanguages (searchText , tenantsToQuery );
218+ case "countries" -> getCountries ();
214219 case "tenant_id" -> getTenantIds (entityType );
215220 case "tenant_name" -> getTenantNames (entityType );
216221 // instructs query builder to provide organization finder plugin, so no values need be returned here
217222 case "organization" , "donor_organization" -> ColumnValues .builder ().content (List .of ()).build ();
218- default -> throw new InvalidEntityTypeDefinitionException ("Unhandled source name \" " + field .getSource ().getName () + "\" for the FQM value source type in column \" " + fieldName + '"' , entityType );
223+ default -> throw new InvalidEntityTypeDefinitionException ("Unhandled source name \" "
224+ + field .getSource ().getName () + "\" for the FQM value source type in column \" "
225+ + fieldName + '"' , entityType );
219226 };
220227 }
221228 }
@@ -309,8 +316,7 @@ private ColumnValues getFieldValuesFromApi(Field field, String searchText, List<
309316 log .error ("Failed to get column values from {} tenant due to exception:" , tenantId , e );
310317 failureCount ++;
311318 lastException = e ;
312- }
313- catch (FeignException .NotFound e ) {
319+ } catch (FeignException .NotFound e ) {
314320 log .error ("Value source API {} not found in tenant {}" , field .getValueSourceApi ().getPath (), tenantId );
315321 failureCount ++;
316322 lastException = e ;
@@ -433,6 +439,40 @@ private ColumnValues getLanguages(String searchText, List<String> tenantsToQuery
433439 return new ColumnValues ().content (results );
434440 }
435441
442+ private ColumnValues getCountries () {
443+ ObjectMapper mapper = new ObjectMapper ();
444+ try (InputStream input = getClass ().getClassLoader ().getResourceAsStream (COUNTRIES_FILEPATH )) {
445+ if (input == null ) {
446+ log .warn ("Country code file {} not found on classpath" , COUNTRIES_FILEPATH );
447+ return new ColumnValues ().content (List .of ());
448+ }
449+
450+ // List of ISO 3166-1 alpha-2 codes
451+ List <String > codes = mapper .readValue (input , new TypeReference <>() {
452+ });
453+
454+ List <ValueWithLabel > values = codes .stream ()
455+ .map (code -> {
456+ String translationKey = COUNTRY_TRANSLATION_TEMPLATE .formatted (code );
457+ String label = translationService .format (translationKey );
458+
459+ // Use original code as label if translation is missing
460+ if (label == null || StringUtils .isBlank (label ) || label .equals (translationKey )) {
461+ label = code ;
462+ }
463+
464+ return new ValueWithLabel ().value (code ).label (label );
465+ })
466+ .sorted (comparing (ValueWithLabel ::getLabel , String .CASE_INSENSITIVE_ORDER ))
467+ .toList ();
468+
469+ return new ColumnValues ().content (values );
470+ } catch (IOException e ) {
471+ log .warn ("Failed to read countries from {}" , COUNTRIES_FILEPATH , e );
472+ return new ColumnValues ().content (List .of ());
473+ }
474+ }
475+
436476 private static ValueWithLabel toValueWithLabel (Map <String , Object > allValues , String fieldName ) {
437477 var valueWithLabel = new ValueWithLabel ().label (getFieldValue (allValues , fieldName ));
438478 return allValues .containsKey (ID_FIELD_NAME )
@@ -688,7 +728,7 @@ static List<JoinFieldPair> discoverJoinConditions(EntityType customEntityType, E
688728 }
689729 return joinConditions .stream ()
690730 .sorted (comparing ((JoinFieldPair pair ) -> pair .getSourceField ().getLabel (), String .CASE_INSENSITIVE_ORDER )
691- .thenComparing (pair -> pair .getTargetField ().getLabel (), String .CASE_INSENSITIVE_ORDER ))
731+ .thenComparing (pair -> pair .getTargetField ().getLabel (), String .CASE_INSENSITIVE_ORDER ))
692732 .toList ();
693733 }
694734
0 commit comments