44import java .io .InputStream ;
55import java .nio .file .Files ;
66import java .nio .file .Path ;
7+ import java .text .MessageFormat ;
78import java .util .HashMap ;
89import java .util .List ;
910import java .util .Map ;
1011import java .util .Objects ;
1112import java .util .Optional ;
12- import java .util .Set ;
1313import java .util .stream .Collectors ;
1414import java .util .stream .Stream ;
15+ import org .apache .commons .io .FilenameUtils ;
1516import org .apache .commons .lang3 .StringUtils ;
17+ import org .apache .commons .lang3 .Validate ;
18+ import org .apache .commons .lang3 .tuple .Pair ;
19+ import org .slf4j .Logger ;
20+ import org .slf4j .LoggerFactory ;
1621import com .helger .genericode .Genericode10CodeListMarshaller ;
1722import com .helger .genericode .v10 .CodeListDocument ;
1823import com .helger .genericode .v10 .Identification ;
1924import com .helger .genericode .v10 .LongName ;
20- import com .helger .genericode .v10 .SimpleCodeList ;
2125import eu .europa .ted .eforms .sdk .entity .SdkCodelist ;
2226import eu .europa .ted .eforms .sdk .entity .SdkEntityFactory ;
2327import eu .europa .ted .util .GenericodeTools ;
2428
2529public class SdkCodelistRepository extends HashMap <String , SdkCodelist > {
2630 private static final long serialVersionUID = 1L ;
2731
28- private transient Path codelistsPath ;
32+ private static final Logger logger = LoggerFactory .getLogger (SdkCodelistRepository .class );
33+
34+ private transient Path codelistsDir ;
2935 private String sdkVersion ;
3036
37+ private final Map <String , Path > codelistFilesByCodelistId ;
38+ private final Genericode10CodeListMarshaller marshaller ;
39+
3140 @ SuppressWarnings ("unused" )
3241 private SdkCodelistRepository () {
3342 throw new UnsupportedOperationException ();
3443 }
3544
36- public SdkCodelistRepository (String sdkVersion , Path codelistsPath ) {
45+ public SdkCodelistRepository (String sdkVersion , Path codelistsDir ) {
3746 this .sdkVersion = sdkVersion ;
38- this .codelistsPath = codelistsPath ;
47+ this .codelistsDir = codelistsDir ;
48+
49+ marshaller = GenericodeTools .getMarshaller ();
50+
51+ try {
52+ this .codelistFilesByCodelistId = getCodelistPaths (codelistsDir );
53+ } catch (IOException e ) {
54+ throw new RuntimeException (
55+ MessageFormat .format ("Failed to load codelists from [{0}]" , codelistsDir ), e );
56+ }
3957 }
4058
4159 /**
@@ -53,7 +71,7 @@ public final SdkCodelist get(final Object codelistId) {
5371
5472 return computeIfAbsent ((String ) codelistId , key -> {
5573 try {
56- return loadSdkCodelist (sdkVersion , key , codelistsPath );
74+ return loadSdkCodelist (sdkVersion , key );
5775 } catch (InstantiationException e ) {
5876 throw new RuntimeException (e );
5977 }
@@ -62,48 +80,53 @@ public final SdkCodelist get(final Object codelistId) {
6280
6381 @ Override
6482 public SdkCodelist getOrDefault (final Object codelistId , final SdkCodelist defaultValue ) {
65- return computeIfAbsent ((String ) codelistId , key -> {
66- try {
67- return loadSdkCodelist (sdkVersion , key , codelistsPath );
68- } catch (InstantiationException e ) {
69- throw new RuntimeException (e );
70- }
71- });
83+ SdkCodelist result = get (codelistId );
84+ return result != null ? result : defaultValue ;
7285 }
7386
74- private static SdkCodelist loadSdkCodelist (final String sdkVersion , final String codeListId ,
75- final Path codelistsPath ) throws InstantiationException {
87+ private SdkCodelist loadSdkCodelist (final String sdkVersion , final String codeListId )
88+ throws InstantiationException {
89+ logger .debug ("Loading SDK codelist with ID [{}] for SDK version [{}] from path [{}]" ,
90+ codeListId , sdkVersion , codelistsDir );
91+
7692 // Find the SDK codelist .gc file that corresponds to the passed reference.
7793 // Stream the data from that file.
7894 final Genericode10CodeListMarshaller marshaller = GenericodeTools .getMarshaller ();
79- final Map <String , String > codelistIdToFilename ;
80- try {
81- codelistIdToFilename = buildMapCodelistIdToFilename (codelistsPath , marshaller );
82- } catch (IOException e1 ) {
83- throw new RuntimeException (e1 );
84- }
85- final String filename = codelistIdToFilename .get (codeListId );
86- assert filename != null : "filename is null" ;
87- try (InputStream is = Files .newInputStream (codelistsPath .resolve (Path .of (filename )))) {
88- final CodeListDocument cl = marshaller .read (is );
89- final SimpleCodeList scl = cl .getSimpleCodeList ();
9095
91- // Version tag of the genericode (gc) file.
92- final String codelistVersion = cl .getIdentification ().getVersion ();
93- final Optional <String > parentId = extractParentId (cl .getIdentification ());
96+ final Path filepath = codelistFilesByCodelistId .get (codeListId );
97+ assert filepath != null : "filepath is null" ;
98+
99+ try (InputStream is = Files .newInputStream (codelistsDir .resolve (filepath ))) {
100+ final CodeListDocument codelist = marshaller .read (is );
94101
95102 // Get all the code values in a list.
96103 // We assume there are no duplicate code values in the referenced
97104 // codelists.
98- final List <String > codes = scl .getRow ().stream ().map (row -> {
99- return row .getValue ().stream ()
100- .filter (v -> GenericodeTools .KEY_CODE .equals (GenericodeTools .extractColRefId (v )))
101- .findFirst ()//
102- .orElseThrow (RuntimeException ::new )//
103- .getSimpleValue ()//
104- .getValue ().strip ();
105- }).collect (Collectors .toList ());
106- return SdkEntityFactory .getSdkCodelist (sdkVersion , codeListId , codelistVersion , codes , parentId );
105+ final List <String > codes = codelist
106+ .getSimpleCodeList ()
107+ .getRow ().stream ()
108+ .map (row -> row .getValue ().stream ()
109+ .filter (v -> GenericodeTools .KEY_CODE .equals (GenericodeTools .extractColRefId (v )))
110+ .findFirst ()
111+ .orElseThrow (RuntimeException ::new )
112+ .getSimpleValue ()
113+ .getValue ()
114+ .strip ())
115+ .collect (Collectors .toList ());
116+
117+ // Version tag of the genericode (gc) file.
118+ final String codelistVersion = codelist .getIdentification ().getVersion ();
119+
120+ final Optional <String > parentId = extractParentId (codelist .getIdentification ());
121+
122+ SdkCodelist result =
123+ SdkEntityFactory .getSdkCodelist (sdkVersion , codeListId , codelistVersion , codes ,
124+ parentId );
125+
126+ logger .debug ("Finished loading SDK codelist with ID [{}] for SDK version [{}] from path [{}]" ,
127+ codeListId , sdkVersion , codelistsDir );
128+
129+ return result ;
107130 } catch (final IOException e ) {
108131 throw new RuntimeException (e );
109132 }
@@ -122,43 +145,43 @@ public static final Optional<String> extractParentId(final Identification ident)
122145 public static Optional <String > extractLongNameWithIdentifier (final Identification identity ,
123146 final String identifierStr ) {
124147 final Optional <LongName > valueOpt = identity .getLongName ().stream ()
125- .filter (item -> Objects .equals (item .getIdentifier (), identifierStr ))//
148+ .filter (item -> Objects .equals (item .getIdentifier (), identifierStr ))
126149 .findFirst ();
150+
127151 if (valueOpt .isPresent ()) {
128152 final String parentId = valueOpt .get ().getValue ();
129153 return StringUtils .isBlank (parentId ) ? Optional .empty () : Optional .of (parentId .strip ());
130154 }
155+
131156 return Optional .empty ();
132157 }
133158
134- private static Map <String , String > buildMapCodelistIdToFilename (final Path pathFolder ,
135- final Genericode10CodeListMarshaller marshaller ) throws IOException {
159+ private Map <String , Path > getCodelistPaths (final Path pathFolder ) throws IOException {
136160 final int depth = 1 ; // Flat folder, not recursive for now.
137- return getFilePathsAsSet (pathFolder , depth , GenericodeTools .EXTENSION_DOT_GC )//
138- // .parallelStream() // Overkill and also messes with logs order.
139- .stream ().map (path -> {
140- final CodeListDocument cl = marshaller .read (path );
141- final Identification identification = cl .getIdentification ();
142- // We use the longName as a ID, PK in the the DB.
143- // But for the filenames we do not always follow this convention.
144- // So we need to map.
145- final String longNameStr = identification .getLongNameAtIndex (0 ).getValue ();
146- final String fileNameStr = path .getFileName ().toString ();
147- return Map .entry (longNameStr , fileNameStr );
148- }).collect (Collectors .toMap (e -> e .getKey (), e -> e .getValue ()));
149- }
150161
151- @ edu .umd .cs .findbugs .annotations .SuppressFBWarnings (
152- value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" , justification = "False positive." )
153- private static Set <Path > getFilePathsAsSet (final Path pathFolder , final int depth ,
154- final String extension ) throws IOException {
155- if (!pathFolder .toFile ().isDirectory ()) {
156- throw new RuntimeException (String .format ("Expecting folder but got: %s" , pathFolder ));
157- }
158- try (Stream <Path > stream = Files .walk (pathFolder , depth )) {
159- return stream .filter (pathFile -> !Files .isDirectory (pathFile )//
160- && pathFile .toString ().endsWith (extension ))//
161- .collect (Collectors .toSet ());
162+ Validate .isTrue (Files .isDirectory (pathFolder ),
163+ MessageFormat .format ("Not a directory: {0}" , pathFolder ));
164+
165+ try (Stream <Path > walk = Files .walk (pathFolder , depth )) {
166+ return walk
167+ .filter (this ::isGenericodeFile )
168+ .map ((Path path ) -> {
169+ final CodeListDocument cl = marshaller .read (path );
170+ // We use the longName as a ID, PK in the the DB.
171+ // But for the filenames we do not always follow this convention.
172+ // So we need to map.
173+ final String longName = cl .getIdentification ().getLongNameAtIndex (0 ).getValue ();
174+
175+ return Pair .of (longName , path );
176+ })
177+ .collect (Collectors .toMap (Pair ::getKey , Pair ::getValue ));
162178 }
163179 }
180+
181+ private boolean isGenericodeFile (final Path path ) {
182+ return path != null
183+ && Files .isRegularFile (path )
184+ && GenericodeTools .EXTENSION_DOT_GC
185+ .equals (MessageFormat .format (".{0}" , FilenameUtils .getExtension (path .toString ())));
186+ }
164187}
0 commit comments