Revize 7bf2464a
Přidáno uživatelem Jakub Šmíd před téměř 3 roky(ů)
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItem.java | ||
---|---|---|
119 | 119 |
|
120 | 120 |
this.name = csvFields.get(1); |
121 | 121 |
Set<String> stringList = processListField(csvFields.get(2)); |
122 |
stringList.add(this.name); |
|
122 | 123 |
this.alternativeNames = stringList.stream().map(s -> new AlternativeName(s, this)).collect(Collectors.toSet()); |
123 | 124 |
|
124 | 125 |
this.certainty = processIntField(csvFields.get(3)); |
backend/src/main/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImpl.java | ||
---|---|---|
224 | 224 |
} |
225 | 225 |
|
226 | 226 |
/** |
227 |
* Converts catalog DTO to catalog entity
|
|
227 |
* Converts catalog item DTO to catalog item entity
|
|
228 | 228 |
* |
229 |
* @param catalogItemDto catalog DTO |
|
230 |
* @param catalogItem catalog entity |
|
229 |
* @param catalogItemDto catalog item DTO
|
|
230 |
* @param catalogItem catalog item entity
|
|
231 | 231 |
*/ |
232 | 232 |
private void convertDtoToEntity(CatalogItemDto catalogItemDto, CatalogItem catalogItem) { |
233 | 233 |
catalogItem.setName(catalogItemDto.getName()); |
... | ... | |
247 | 247 |
catalogItem.getCountries().addAll(catalogItemDto.getCountries() |
248 | 248 |
.stream().map(s -> new Country(s, catalogItem)).collect(Collectors.toSet())); |
249 | 249 |
|
250 |
catalogItemDto.getAlternativeNames().add(catalogItemDto.getName()); |
|
250 | 251 |
catalogItem.getAlternativeNames().clear(); |
251 | 252 |
catalogItem.getAlternativeNames().addAll(catalogItemDto.getAlternativeNames() |
252 | 253 |
.stream().map(s -> new AlternativeName(s, catalogItem)).collect(Collectors.toSet())); |
... | ... | |
259 | 260 |
} |
260 | 261 |
|
261 | 262 |
/** |
262 |
* Converts catalog entity to catalog DTO
|
|
263 |
* Converts catalog item entity to catalog item DTO
|
|
263 | 264 |
* |
264 |
* @param catalogItem catalog entity |
|
265 |
* @return catalog DTO |
|
265 |
* @param catalogItem catalog item entity
|
|
266 |
* @return catalog item DTO
|
|
266 | 267 |
*/ |
267 | 268 |
private CatalogItemDto convertEntityToDto(CatalogItem catalogItem) { |
268 | 269 |
CatalogItemDto catalogItemDto = new CatalogItemDto(); |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogController.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.external; |
2 | 2 |
|
3 |
import io.swagger.v3.oas.annotations.Operation; |
|
3 | 4 |
import lombok.RequiredArgsConstructor; |
4 |
import org.springframework.web.bind.annotation.PostMapping; |
|
5 |
import org.springframework.web.bind.annotation.RequestMapping; |
|
6 |
import org.springframework.web.bind.annotation.RestController; |
|
5 |
import org.springframework.http.HttpStatus; |
|
6 |
import org.springframework.http.ResponseEntity; |
|
7 |
import org.springframework.web.bind.annotation.*; |
|
8 |
|
|
9 |
import java.util.List; |
|
7 | 10 |
|
8 | 11 |
/** |
9 | 12 |
* Controller for external catalog |
... | ... | |
16 | 19 |
/** |
17 | 20 |
* External catalog service |
18 | 21 |
*/ |
19 |
private final IExternalCatalogService externalCatalogService; |
|
22 |
private final IExternalCatalogItemService externalCatalogService;
|
|
20 | 23 |
|
21 | 24 |
@PostMapping("") |
25 |
@Operation(summary = "updates external catalog") |
|
22 | 26 |
public void updateCatalog() { |
23 | 27 |
externalCatalogService.updateCatalog(); |
24 | 28 |
} |
29 |
|
|
30 |
/** |
|
31 |
* Returns external catalog items satisfying given filter |
|
32 |
* |
|
33 |
* @param name name |
|
34 |
* @param source source |
|
35 |
* @return list of external catalog items satisfying given filter |
|
36 |
*/ |
|
37 |
@GetMapping("") |
|
38 |
@Operation(summary = "returns external catalog items based on filter") |
|
39 |
public ResponseEntity<List<ExternalCatalogItem>> getCatalog(@RequestParam String name, @RequestParam ExternalSource source) { |
|
40 |
return new ResponseEntity<>(externalCatalogService.getCatalog(name, source), HttpStatus.OK); |
|
41 |
} |
|
25 | 42 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogItem.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.external; |
2 | 2 |
|
3 |
import lombok.EqualsAndHashCode; |
|
4 |
import lombok.Getter; |
|
5 |
import lombok.NoArgsConstructor; |
|
6 |
import lombok.Setter; |
|
3 |
import io.swagger.v3.oas.annotations.media.Schema; |
|
4 |
import lombok.*; |
|
7 | 5 |
|
8 | 6 |
import javax.persistence.*; |
9 | 7 |
import java.util.*; |
... | ... | |
18 | 16 |
@Setter |
19 | 17 |
@EqualsAndHashCode(onlyExplicitlyIncluded = true) |
20 | 18 |
@NoArgsConstructor |
19 |
@AllArgsConstructor |
|
21 | 20 |
@Entity |
22 | 21 |
@Table(name = "external_catalog_items") |
22 |
@Schema(name = "ExternalCatalogItemDto") |
|
23 | 23 |
public class ExternalCatalogItem { |
24 | 24 |
/** |
25 | 25 |
* Map where key is country code and value is name of country |
... | ... | |
116 | 116 |
@Column(length = 20000) |
117 | 117 |
private Set<String> names = new HashSet<>(); |
118 | 118 |
|
119 |
|
|
119 | 120 |
/** |
120 | 121 |
* Feature code |
121 | 122 |
*/ |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogItemItemServiceImpl.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import com.zaxxer.hikari.HikariDataSource; |
|
4 |
import lombok.RequiredArgsConstructor; |
|
5 |
import lombok.extern.slf4j.Slf4j; |
|
6 |
import org.apache.commons.csv.CSVFormat; |
|
7 |
import org.apache.commons.csv.CSVParser; |
|
8 |
import org.apache.commons.csv.CSVRecord; |
|
9 |
import org.apache.tomcat.util.http.fileupload.FileUtils; |
|
10 |
import org.springframework.stereotype.Service; |
|
11 |
import org.springframework.transaction.annotation.Transactional; |
|
12 |
|
|
13 |
import javax.persistence.Table; |
|
14 |
import java.io.*; |
|
15 |
import java.net.URL; |
|
16 |
import java.nio.charset.StandardCharsets; |
|
17 |
import java.nio.file.Files; |
|
18 |
import java.nio.file.Paths; |
|
19 |
import java.sql.Connection; |
|
20 |
import java.sql.PreparedStatement; |
|
21 |
import java.util.ArrayList; |
|
22 |
import java.util.List; |
|
23 |
import java.util.concurrent.Callable; |
|
24 |
import java.util.concurrent.ExecutorService; |
|
25 |
import java.util.concurrent.Executors; |
|
26 |
import java.util.stream.Collectors; |
|
27 |
import java.util.zip.GZIPInputStream; |
|
28 |
import java.util.zip.ZipEntry; |
|
29 |
import java.util.zip.ZipInputStream; |
|
30 |
|
|
31 |
/** |
|
32 |
* External catalog item service implementation |
|
33 |
*/ |
|
34 |
@Service |
|
35 |
@Transactional |
|
36 |
@RequiredArgsConstructor |
|
37 |
@Slf4j |
|
38 |
public class ExternalCatalogItemItemServiceImpl implements IExternalCatalogItemService { |
|
39 |
/** |
|
40 |
* Buffer size |
|
41 |
*/ |
|
42 |
public static final int BUFFER_SIZE = 1024; |
|
43 |
/** |
|
44 |
* Directory where files for external directory will be stored |
|
45 |
*/ |
|
46 |
private static final String DIRECTORY_FOR_EXTERNAL_FILES = "sources"; |
|
47 |
/** |
|
48 |
* URL for Pleiades file |
|
49 |
*/ |
|
50 |
private static final String PLEIADES_FILE_URL = "https://atlantides.org/downloads/pleiades/dumps/pleiades-names-latest.csv.gz"; |
|
51 |
/** |
|
52 |
* Name of Pleiades file |
|
53 |
*/ |
|
54 |
private static final String PLEIADES_FILE_NAME = "pleiades-names-latest.csv"; |
|
55 |
/** |
|
56 |
* URL for Pleiades file – needs to be formatted (more sources) |
|
57 |
*/ |
|
58 |
private static final String GEONAMES_FILE_URL = "https://download.geonames.org/export/dump/%s.zip"; |
|
59 |
/** |
|
60 |
* Name of GeoNames file – needs to be formatted (more sources) |
|
61 |
*/ |
|
62 |
private static final String GEONAMES_FILE_NAME = "%s.txt"; |
|
63 |
/** |
|
64 |
* URL for CIGS file |
|
65 |
*/ |
|
66 |
private static final String CIGS_FILE_URL = "https://zenodo.org/record/5642899/files/CIGS_v1_4_20211101.csv"; |
|
67 |
/** |
|
68 |
* Name of CIGS file |
|
69 |
*/ |
|
70 |
private static final String CIGS_FILE_NAME = "CIGS_v1_4_20211101.csv"; |
|
71 |
/** |
|
72 |
* Batch size for saving items |
|
73 |
*/ |
|
74 |
private static final int BATCH_SIZE = 5000; |
|
75 |
|
|
76 |
/** |
|
77 |
* Regex for one arbitrary character in string |
|
78 |
*/ |
|
79 |
private static final String WILDCARD_CHARACTER_REGEX = "\\?"; |
|
80 |
|
|
81 |
/** |
|
82 |
* Regex for one arbitrary character in string used in SQL |
|
83 |
*/ |
|
84 |
private static final String WILDCARD_CHARACTER_REGEX_SQL = "_"; |
|
85 |
|
|
86 |
/** |
|
87 |
* Regex for any number of arbitrary characters in string |
|
88 |
*/ |
|
89 |
private static final String WILDCARD_CHARACTERS_REGEX = "\\*"; |
|
90 |
|
|
91 |
/** |
|
92 |
* Regex for any number of arbitrary characters in string used in SQL |
|
93 |
*/ |
|
94 |
private static final String WILDCARD_CHARACTERS_REGEX_SQL = "%"; |
|
95 |
|
|
96 |
/** |
|
97 |
* External catalog repository |
|
98 |
*/ |
|
99 |
private final ExternalCatalogItemRepository externalCatalogItemRepository; |
|
100 |
|
|
101 |
/** |
|
102 |
* Hikari data source |
|
103 |
*/ |
|
104 |
private final HikariDataSource hikariDataSource; |
|
105 |
|
|
106 |
/** |
|
107 |
* Set to string convertor |
|
108 |
*/ |
|
109 |
private final SetToStringConverter setToStringConverter; |
|
110 |
|
|
111 |
|
|
112 |
@Override |
|
113 |
public void updateCatalog() { |
|
114 |
log.info("Updating external catalog"); |
|
115 |
try { |
|
116 |
Files.createDirectories(Paths.get(DIRECTORY_FOR_EXTERNAL_FILES)); // creates directory if not exists |
|
117 |
FileUtils.cleanDirectory(new File(DIRECTORY_FOR_EXTERNAL_FILES)); // cleans the directory |
|
118 |
externalCatalogItemRepository.deleteAll(); // clears database – updated list will be stored later |
|
119 |
addPleiadesSource(); |
|
120 |
addGeonamesSources(); |
|
121 |
addCigsSources(); |
|
122 |
} catch (Exception e) { |
|
123 |
e.printStackTrace(); |
|
124 |
} |
|
125 |
log.info("External catalog updated"); |
|
126 |
} |
|
127 |
|
|
128 |
@Override |
|
129 |
public List<ExternalCatalogItem> getCatalog(String name, ExternalSource source) { |
|
130 |
name = WILDCARD_CHARACTERS_REGEX_SQL + |
|
131 |
name.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_SQL).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_SQL) + |
|
132 |
WILDCARD_CHARACTERS_REGEX_SQL; |
|
133 |
return externalCatalogItemRepository.getFilteredExternalCatalog(name, source.name()); |
|
134 |
} |
|
135 |
|
|
136 |
/** |
|
137 |
* Downloads, extracts and reads Pleiades sources and saves them to database |
|
138 |
*/ |
|
139 |
private void addPleiadesSource() { |
|
140 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
141 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
142 |
File pleiadesFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), PLEIADES_FILE_NAME); |
|
143 |
try (InputStream fileIn = new URL(PLEIADES_FILE_URL).openStream(); |
|
144 |
GZIPInputStream gZIPInputStream = new GZIPInputStream(fileIn); |
|
145 |
FileOutputStream fileOutputStream = new FileOutputStream(pleiadesFile)) { |
|
146 |
|
|
147 |
int bytes_read; |
|
148 |
|
|
149 |
while ((bytes_read = gZIPInputStream.read(buffer)) > 0) { |
|
150 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
151 |
} |
|
152 |
|
|
153 |
log.info("The Pleiades file was decompressed successfully"); |
|
154 |
|
|
155 |
} catch (IOException ex) { |
|
156 |
ex.printStackTrace(); |
|
157 |
} |
|
158 |
|
|
159 |
try (InputStream csvData = new FileInputStream(pleiadesFile)) { |
|
160 |
CSVParser parser = CSVParser.parse(csvData, StandardCharsets.UTF_8, CSVFormat.Builder.create(CSVFormat.DEFAULT) |
|
161 |
.setHeader() |
|
162 |
.setSkipHeaderRecord(true) |
|
163 |
.build()); |
|
164 |
for (CSVRecord csvRecord : parser) { |
|
165 |
ExternalCatalogItem e = new ExternalCatalogItem(csvRecord.toList(), ExternalSource.PLEIADES); |
|
166 |
externalCatalogItems.add(e); |
|
167 |
} |
|
168 |
|
|
169 |
} catch (IOException ex) { |
|
170 |
ex.printStackTrace(); |
|
171 |
} |
|
172 |
saveAllWithThreads(externalCatalogItems); |
|
173 |
} |
|
174 |
|
|
175 |
/** |
|
176 |
* Downloads, extracts and reads GeoNames sources and saves them to database |
|
177 |
*/ |
|
178 |
private void addGeonamesSources() { |
|
179 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
180 |
for (String countryCode : ExternalCatalogItem.COUNTRY_CODES.keySet()) { |
|
181 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
182 |
// Downloads file from URL and extracts it |
|
183 |
String url = String.format(GEONAMES_FILE_URL, countryCode); |
|
184 |
try (ZipInputStream zis = new ZipInputStream(new URL(url).openStream())) { |
|
185 |
ZipEntry zipEntry = zis.getNextEntry(); |
|
186 |
while (zipEntry != null) { |
|
187 |
FileOutputStream fileOutputStream = new FileOutputStream(new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), zipEntry.getName())); |
|
188 |
int bytes_read; |
|
189 |
while ((bytes_read = zis.read(buffer)) > 0) { |
|
190 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
191 |
} |
|
192 |
zipEntry = zis.getNextEntry(); |
|
193 |
fileOutputStream.close(); |
|
194 |
} |
|
195 |
} catch (IOException e) { |
|
196 |
e.printStackTrace(); |
|
197 |
} |
|
198 |
|
|
199 |
log.info("The GeoNames file with country code " + countryCode + " was decompressed successfully"); |
|
200 |
|
|
201 |
// Reads file and adds catalog items to list |
|
202 |
File geoNamesFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), String.format(GEONAMES_FILE_NAME, countryCode)); |
|
203 |
try (BufferedReader reader = new BufferedReader(new FileReader(geoNamesFile))) { |
|
204 |
String line; |
|
205 |
while ((line = reader.readLine()) != null) { |
|
206 |
ExternalCatalogItem e = new ExternalCatalogItem(List.of(line.split("\t")), ExternalSource.GEONAMES); |
|
207 |
externalCatalogItems.add(e); |
|
208 |
} |
|
209 |
} catch (IOException e) { |
|
210 |
e.printStackTrace(); |
|
211 |
} |
|
212 |
saveAllWithThreads(externalCatalogItems); |
|
213 |
} |
|
214 |
} |
|
215 |
|
|
216 |
/** |
|
217 |
* Downloads and reads CIGS sources and saves them to database |
|
218 |
*/ |
|
219 |
private void addCigsSources() { |
|
220 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
221 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
222 |
File cigsFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), CIGS_FILE_NAME); |
|
223 |
|
|
224 |
try (InputStream inputStream = new URL(CIGS_FILE_URL).openStream(); |
|
225 |
FileOutputStream fileOutputStream = new FileOutputStream(cigsFile)) { |
|
226 |
int bytes_read; |
|
227 |
|
|
228 |
while ((bytes_read = inputStream.read(buffer)) > 0) { |
|
229 |
|
|
230 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
231 |
} |
|
232 |
} catch (IOException e) { |
|
233 |
e.printStackTrace(); |
|
234 |
} |
|
235 |
|
|
236 |
log.info("The CIGS file was downloaded successfully"); |
|
237 |
|
|
238 |
try (InputStream csvData = new FileInputStream(cigsFile)) { |
|
239 |
CSVParser parser = CSVParser.parse(csvData, StandardCharsets.UTF_8, CSVFormat.Builder.create(CSVFormat.DEFAULT) |
|
240 |
.setHeader() |
|
241 |
.setSkipHeaderRecord(true) |
|
242 |
.build()); |
|
243 |
for (CSVRecord csvRecord : parser) { |
|
244 |
ExternalCatalogItem e = new ExternalCatalogItem(csvRecord.toList(), ExternalSource.CIGS); |
|
245 |
externalCatalogItems.add(e); |
|
246 |
} |
|
247 |
} catch (IOException e) { |
|
248 |
e.printStackTrace(); |
|
249 |
} |
|
250 |
saveAllWithThreads(externalCatalogItems); |
|
251 |
} |
|
252 |
|
|
253 |
/** |
|
254 |
* Creates list of lists of external catalog items divided by batch size |
|
255 |
* |
|
256 |
* @param externalCatalogItems list of external catalog items |
|
257 |
* @return divided list of lists of external catalog items |
|
258 |
*/ |
|
259 |
private List<List<ExternalCatalogItem>> createSublist(List<ExternalCatalogItem> externalCatalogItems) { |
|
260 |
List<List<ExternalCatalogItem>> listOfSubList = new ArrayList<>(); |
|
261 |
for (int i = 0; i < externalCatalogItems.size(); i += BATCH_SIZE) { |
|
262 |
if (i + BATCH_SIZE <= externalCatalogItems.size()) { |
|
263 |
listOfSubList.add(externalCatalogItems.subList(i, i + BATCH_SIZE)); |
|
264 |
} else { |
|
265 |
listOfSubList.add(externalCatalogItems.subList(i, externalCatalogItems.size())); |
|
266 |
} |
|
267 |
} |
|
268 |
return listOfSubList; |
|
269 |
} |
|
270 |
|
|
271 |
/** |
|
272 |
* Divides list of external catalog items to sublist, creates threads (for saving sublists in batch) and executes them |
|
273 |
* |
|
274 |
* @param externalCatalogItems list of external catalog items |
|
275 |
*/ |
|
276 |
private void saveAllWithThreads(List<ExternalCatalogItem> externalCatalogItems) { |
|
277 |
ExecutorService executorService = Executors.newFixedThreadPool(hikariDataSource.getMaximumPoolSize()); |
|
278 |
List<List<ExternalCatalogItem>> subList = createSublist(externalCatalogItems); |
|
279 |
List<Callable<Void>> callables = subList.stream().map(sublist -> |
|
280 |
(Callable<Void>) () -> { |
|
281 |
saveAllInBatch(sublist); |
|
282 |
return null; |
|
283 |
}).collect(Collectors.toList()); |
|
284 |
try { |
|
285 |
executorService.invokeAll(callables); |
|
286 |
} catch (InterruptedException e) { |
|
287 |
e.printStackTrace(); |
|
288 |
} |
|
289 |
} |
|
290 |
|
|
291 |
/** |
|
292 |
* Saves external catalog items in batch |
|
293 |
* |
|
294 |
* @param externalCatalogItems list of external catalog items |
|
295 |
*/ |
|
296 |
private void saveAllInBatch(List<ExternalCatalogItem> externalCatalogItems) { |
|
297 |
String sqlExternalCatalogItem = String.format("INSERT INTO %s (id, external_source, latitude, longitude, location_precision, max_date, " + |
|
298 |
"min_date, time_period_keys, pid, names, feature_code, country, accuracy, geoname_id, pleiades_id, osm_id) " + |
|
299 |
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ExternalCatalogItem.class.getAnnotation(Table.class).name()); |
|
300 |
try (Connection connection = hikariDataSource.getConnection(); |
|
301 |
PreparedStatement statementExternalCatalogItem = connection.prepareStatement(sqlExternalCatalogItem)) { |
|
302 |
int counter = 0; |
|
303 |
for (ExternalCatalogItem item : externalCatalogItems) { |
|
304 |
statementExternalCatalogItem.clearParameters(); |
|
305 |
statementExternalCatalogItem.setObject(1, item.getId()); |
|
306 |
statementExternalCatalogItem.setString(2, item.getExternalSource().name()); |
|
307 |
statementExternalCatalogItem.setObject(3, item.getLatitude()); |
|
308 |
statementExternalCatalogItem.setObject(4, item.getLongitude()); |
|
309 |
statementExternalCatalogItem.setString(5, item.getLocationPrecision()); |
|
310 |
statementExternalCatalogItem.setObject(6, item.getMaxDate()); |
|
311 |
statementExternalCatalogItem.setObject(7, item.getMinDate()); |
|
312 |
statementExternalCatalogItem.setString(8, item.getTimePeriodKeys()); |
|
313 |
statementExternalCatalogItem.setString(9, item.getPid()); |
|
314 |
statementExternalCatalogItem.setString(10, setToStringConverter.convertToDatabaseColumn(item.getNames())); |
|
315 |
statementExternalCatalogItem.setString(11, item.getFeatureCode()); |
|
316 |
statementExternalCatalogItem.setString(12, item.getCountry()); |
|
317 |
statementExternalCatalogItem.setObject(13, item.getAccuracy()); |
|
318 |
statementExternalCatalogItem.setObject(14, item.getGeonameId()); |
|
319 |
statementExternalCatalogItem.setObject(15, item.getPleiadesId()); |
|
320 |
statementExternalCatalogItem.setObject(16, item.getOsmId()); |
|
321 |
statementExternalCatalogItem.addBatch(); |
|
322 |
|
|
323 |
counter++; |
|
324 |
if (counter % BATCH_SIZE == 0 || counter == externalCatalogItems.size()) { |
|
325 |
statementExternalCatalogItem.executeBatch(); |
|
326 |
statementExternalCatalogItem.clearBatch(); |
|
327 |
} |
|
328 |
} |
|
329 |
} catch (Exception e) { |
|
330 |
e.printStackTrace(); |
|
331 |
} |
|
332 |
} |
|
333 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogItemRepository.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import org.springframework.data.jpa.repository.JpaRepository; |
|
4 |
import org.springframework.data.jpa.repository.Query; |
|
5 |
import org.springframework.stereotype.Repository; |
|
6 |
|
|
7 |
import java.util.List; |
|
8 |
import java.util.UUID; |
|
9 |
|
|
10 |
/** |
|
11 |
* External catalog repository |
|
12 |
*/ |
|
13 |
@Repository |
|
14 |
public interface ExternalCatalogItemRepository extends JpaRepository<ExternalCatalogItem, UUID> { |
|
15 |
|
|
16 |
/** |
|
17 |
* Returns list of external catalog items satisfying given filter |
|
18 |
* |
|
19 |
* @param name name |
|
20 |
* @param externalSource source |
|
21 |
* @return list of external catalog items satisfying given filter |
|
22 |
*/ |
|
23 |
@Query(value = "SELECT * FROM external_catalog_items e WHERE UPPER(e.names) LIKE UPPER(?1) AND e.external_source = ?2", nativeQuery = true) |
|
24 |
List<ExternalCatalogItem> getFilteredExternalCatalog(String name, String externalSource); |
|
25 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogRepository.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import org.springframework.data.jpa.repository.JpaRepository; |
|
4 |
import org.springframework.stereotype.Repository; |
|
5 |
|
|
6 |
import java.util.UUID; |
|
7 |
|
|
8 |
/** |
|
9 |
* External catalog repository |
|
10 |
*/ |
|
11 |
@Repository |
|
12 |
public interface ExternalCatalogRepository extends JpaRepository<ExternalCatalogItem, UUID> { |
|
13 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/ExternalCatalogServiceImpl.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import com.zaxxer.hikari.HikariDataSource; |
|
4 |
import lombok.RequiredArgsConstructor; |
|
5 |
import lombok.extern.slf4j.Slf4j; |
|
6 |
import org.apache.commons.csv.CSVFormat; |
|
7 |
import org.apache.commons.csv.CSVParser; |
|
8 |
import org.apache.commons.csv.CSVRecord; |
|
9 |
import org.apache.tomcat.util.http.fileupload.FileUtils; |
|
10 |
import org.springframework.stereotype.Service; |
|
11 |
import org.springframework.transaction.annotation.Transactional; |
|
12 |
|
|
13 |
import javax.persistence.Table; |
|
14 |
import java.io.*; |
|
15 |
import java.net.URL; |
|
16 |
import java.nio.charset.StandardCharsets; |
|
17 |
import java.nio.file.Files; |
|
18 |
import java.nio.file.Paths; |
|
19 |
import java.sql.Connection; |
|
20 |
import java.sql.PreparedStatement; |
|
21 |
import java.util.ArrayList; |
|
22 |
import java.util.List; |
|
23 |
import java.util.concurrent.Callable; |
|
24 |
import java.util.concurrent.ExecutorService; |
|
25 |
import java.util.concurrent.Executors; |
|
26 |
import java.util.stream.Collectors; |
|
27 |
import java.util.zip.GZIPInputStream; |
|
28 |
import java.util.zip.ZipEntry; |
|
29 |
import java.util.zip.ZipInputStream; |
|
30 |
|
|
31 |
/** |
|
32 |
* External catalog service implementation |
|
33 |
*/ |
|
34 |
@Service |
|
35 |
@Transactional |
|
36 |
@RequiredArgsConstructor |
|
37 |
@Slf4j |
|
38 |
public class ExternalCatalogServiceImpl implements IExternalCatalogService { |
|
39 |
/** |
|
40 |
* Buffer size |
|
41 |
*/ |
|
42 |
public static final int BUFFER_SIZE = 1024; |
|
43 |
/** |
|
44 |
* Directory where files for external directory will be stored |
|
45 |
*/ |
|
46 |
private static final String DIRECTORY_FOR_EXTERNAL_FILES = "sources"; |
|
47 |
/** |
|
48 |
* URL for Pleiades file |
|
49 |
*/ |
|
50 |
private static final String PLEIADES_FILE_URL = "https://atlantides.org/downloads/pleiades/dumps/pleiades-names-latest.csv.gz"; |
|
51 |
/** |
|
52 |
* Name of Pleiades file |
|
53 |
*/ |
|
54 |
private static final String PLEIADES_FILE_NAME = "pleiades-names-latest.csv"; |
|
55 |
/** |
|
56 |
* URL for Pleiades file – needs to be formatted (more sources) |
|
57 |
*/ |
|
58 |
private static final String GEONAMES_FILE_URL = "https://download.geonames.org/export/dump/%s.zip"; |
|
59 |
/** |
|
60 |
* Name of GeoNames file – needs to be formatted (more sources) |
|
61 |
*/ |
|
62 |
private static final String GEONAMES_FILE_NAME = "%s.txt"; |
|
63 |
/** |
|
64 |
* URL for CIGS file |
|
65 |
*/ |
|
66 |
private static final String CIGS_FILE_URL = "https://zenodo.org/record/5642899/files/CIGS_v1_4_20211101.csv"; |
|
67 |
/** |
|
68 |
* Name of CIGS file |
|
69 |
*/ |
|
70 |
private static final String CIGS_FILE_NAME = "CIGS_v1_4_20211101.csv"; |
|
71 |
/** |
|
72 |
* Batch size for saving items |
|
73 |
*/ |
|
74 |
private static final int BATCH_SIZE = 5000; |
|
75 |
|
|
76 |
/** |
|
77 |
* External catalog repository |
|
78 |
*/ |
|
79 |
private final ExternalCatalogRepository externalCatalogRepository; |
|
80 |
|
|
81 |
/** |
|
82 |
* Hikari data source |
|
83 |
*/ |
|
84 |
private final HikariDataSource hikariDataSource; |
|
85 |
|
|
86 |
|
|
87 |
@Override |
|
88 |
public void updateCatalog() { |
|
89 |
log.info("Updating external catalog"); |
|
90 |
try { |
|
91 |
Files.createDirectories(Paths.get(DIRECTORY_FOR_EXTERNAL_FILES)); // creates directory if not exists |
|
92 |
FileUtils.cleanDirectory(new File(DIRECTORY_FOR_EXTERNAL_FILES)); // cleans the directory |
|
93 |
externalCatalogRepository.deleteAll(); // clears database – updated list will be stored later |
|
94 |
addPleiadesSource(); |
|
95 |
addGeonamesSources(); |
|
96 |
addCigsSources(); |
|
97 |
} catch (IOException e) { |
|
98 |
e.printStackTrace(); |
|
99 |
} |
|
100 |
log.info("External catalog updated"); |
|
101 |
} |
|
102 |
|
|
103 |
/** |
|
104 |
* Downloads, extracts and reads Pleiades sources and saves them to database |
|
105 |
*/ |
|
106 |
private void addPleiadesSource() { |
|
107 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
108 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
109 |
File pleiadesFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), PLEIADES_FILE_NAME); |
|
110 |
try (InputStream fileIn = new URL(PLEIADES_FILE_URL).openStream(); |
|
111 |
GZIPInputStream gZIPInputStream = new GZIPInputStream(fileIn); |
|
112 |
FileOutputStream fileOutputStream = new FileOutputStream(pleiadesFile)) { |
|
113 |
|
|
114 |
int bytes_read; |
|
115 |
|
|
116 |
while ((bytes_read = gZIPInputStream.read(buffer)) > 0) { |
|
117 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
118 |
} |
|
119 |
|
|
120 |
log.info("The Pleiades file was decompressed successfully"); |
|
121 |
|
|
122 |
} catch (IOException ex) { |
|
123 |
ex.printStackTrace(); |
|
124 |
} |
|
125 |
|
|
126 |
try (InputStream csvData = new FileInputStream(pleiadesFile)) { |
|
127 |
CSVParser parser = CSVParser.parse(csvData, StandardCharsets.UTF_8, CSVFormat.Builder.create(CSVFormat.DEFAULT) |
|
128 |
.setHeader() |
|
129 |
.setSkipHeaderRecord(true) |
|
130 |
.build()); |
|
131 |
for (CSVRecord csvRecord : parser) { |
|
132 |
externalCatalogItems.add(new ExternalCatalogItem(csvRecord.toList(), ExternalSource.PLEIADES)); |
|
133 |
} |
|
134 |
|
|
135 |
} catch (IOException ex) { |
|
136 |
ex.printStackTrace(); |
|
137 |
} |
|
138 |
saveAllWithThreads(externalCatalogItems); |
|
139 |
} |
|
140 |
|
|
141 |
/** |
|
142 |
* Downloads, extracts and reads GeoNames sources and saves them to database |
|
143 |
*/ |
|
144 |
private void addGeonamesSources() { |
|
145 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
146 |
for (String countryCode : ExternalCatalogItem.COUNTRY_CODES.keySet()) { |
|
147 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
148 |
// Downloads file from URL and extracts it |
|
149 |
String url = String.format(GEONAMES_FILE_URL, countryCode); |
|
150 |
try (ZipInputStream zis = new ZipInputStream(new URL(url).openStream())) { |
|
151 |
ZipEntry zipEntry = zis.getNextEntry(); |
|
152 |
while (zipEntry != null) { |
|
153 |
FileOutputStream fileOutputStream = new FileOutputStream(new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), zipEntry.getName())); |
|
154 |
int bytes_read; |
|
155 |
while ((bytes_read = zis.read(buffer)) > 0) { |
|
156 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
157 |
} |
|
158 |
zipEntry = zis.getNextEntry(); |
|
159 |
fileOutputStream.close(); |
|
160 |
} |
|
161 |
} catch (IOException e) { |
|
162 |
e.printStackTrace(); |
|
163 |
} |
|
164 |
|
|
165 |
log.info("The Geonames file with country code " + countryCode + " was decompressed successfully"); |
|
166 |
|
|
167 |
// Reads file and adds catalog items to list |
|
168 |
File geoNamesFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), String.format(GEONAMES_FILE_NAME, countryCode)); |
|
169 |
try (BufferedReader reader = new BufferedReader(new FileReader(geoNamesFile))) { |
|
170 |
String line; |
|
171 |
while ((line = reader.readLine()) != null) { |
|
172 |
externalCatalogItems.add(new ExternalCatalogItem(List.of(line.split("\t")), ExternalSource.GEONAMES)); |
|
173 |
} |
|
174 |
} catch (IOException e) { |
|
175 |
e.printStackTrace(); |
|
176 |
} |
|
177 |
saveAllWithThreads(externalCatalogItems); |
|
178 |
} |
|
179 |
} |
|
180 |
|
|
181 |
/** |
|
182 |
* Downloads and reads CIGS sources and saves them to database |
|
183 |
*/ |
|
184 |
private void addCigsSources() { |
|
185 |
List<ExternalCatalogItem> externalCatalogItems = new ArrayList<>(); |
|
186 |
byte[] buffer = new byte[BUFFER_SIZE]; |
|
187 |
File cigsFile = new File(new File(DIRECTORY_FOR_EXTERNAL_FILES), CIGS_FILE_NAME); |
|
188 |
|
|
189 |
try (InputStream inputStream = new URL(CIGS_FILE_URL).openStream(); |
|
190 |
FileOutputStream fileOutputStream = new FileOutputStream(cigsFile)) { |
|
191 |
int bytes_read; |
|
192 |
|
|
193 |
while ((bytes_read = inputStream.read(buffer)) > 0) { |
|
194 |
|
|
195 |
fileOutputStream.write(buffer, 0, bytes_read); |
|
196 |
} |
|
197 |
} catch (IOException e) { |
|
198 |
e.printStackTrace(); |
|
199 |
} |
|
200 |
|
|
201 |
log.info("The CIGS file was downloaded successfully"); |
|
202 |
|
|
203 |
try (InputStream csvData = new FileInputStream(cigsFile)) { |
|
204 |
CSVParser parser = CSVParser.parse(csvData, StandardCharsets.UTF_8, CSVFormat.Builder.create(CSVFormat.DEFAULT) |
|
205 |
.setHeader() |
|
206 |
.setSkipHeaderRecord(true) |
|
207 |
.build()); |
|
208 |
for (CSVRecord csvRecord : parser) { |
|
209 |
externalCatalogItems.add(new ExternalCatalogItem(csvRecord.toList(), ExternalSource.CIGS)); |
|
210 |
} |
|
211 |
} catch (IOException e) { |
|
212 |
e.printStackTrace(); |
|
213 |
} |
|
214 |
saveAllWithThreads(externalCatalogItems); |
|
215 |
} |
|
216 |
|
|
217 |
/** |
|
218 |
* Creates list of lists of external catalog items divided by batch size |
|
219 |
* |
|
220 |
* @param externalCatalogItems list of external catalog items |
|
221 |
* @return divided list of lists of external catalog items |
|
222 |
*/ |
|
223 |
private List<List<ExternalCatalogItem>> createSublist(List<ExternalCatalogItem> externalCatalogItems) { |
|
224 |
List<List<ExternalCatalogItem>> listOfSubList = new ArrayList<>(); |
|
225 |
for (int i = 0; i < externalCatalogItems.size(); i += BATCH_SIZE) { |
|
226 |
if (i + BATCH_SIZE <= externalCatalogItems.size()) { |
|
227 |
listOfSubList.add(externalCatalogItems.subList(i, i + BATCH_SIZE)); |
|
228 |
} else { |
|
229 |
listOfSubList.add(externalCatalogItems.subList(i, externalCatalogItems.size())); |
|
230 |
} |
|
231 |
} |
|
232 |
return listOfSubList; |
|
233 |
} |
|
234 |
|
|
235 |
/** |
|
236 |
* Divides list of external catalog items to sublist, creates threads (for saving sublists in batch) and executes them |
|
237 |
* |
|
238 |
* @param externalCatalogItems list of external catalog items |
|
239 |
*/ |
|
240 |
private void saveAllWithThreads(List<ExternalCatalogItem> externalCatalogItems) { |
|
241 |
ExecutorService executorService = Executors.newFixedThreadPool(hikariDataSource.getMaximumPoolSize()); |
|
242 |
List<List<ExternalCatalogItem>> subList = createSublist(externalCatalogItems); |
|
243 |
List<Callable<Void>> callables = subList.stream().map(sublist -> |
|
244 |
(Callable<Void>) () -> { |
|
245 |
saveAllInBatch(sublist); |
|
246 |
return null; |
|
247 |
}).collect(Collectors.toList()); |
|
248 |
try { |
|
249 |
executorService.invokeAll(callables); |
|
250 |
} catch (InterruptedException e) { |
|
251 |
e.printStackTrace(); |
|
252 |
} |
|
253 |
} |
|
254 |
|
|
255 |
/** |
|
256 |
* Saves external catalog items in batch |
|
257 |
* |
|
258 |
* @param externalCatalogItems list of external catalog items |
|
259 |
*/ |
|
260 |
private void saveAllInBatch(List<ExternalCatalogItem> externalCatalogItems) { |
|
261 |
String sql = String.format("INSERT INTO %s (id, external_source, latitude, longitude, location_precision, max_date, " + |
|
262 |
"min_date, time_period_keys, pid, names, feature_code, country, accuracy, geoname_id, pleiades_id, osm_id) " + |
|
263 |
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ExternalCatalogItem.class.getAnnotation(Table.class).name()); |
|
264 |
try (Connection connection = hikariDataSource.getConnection(); |
|
265 |
PreparedStatement statement = connection.prepareStatement(sql)) { |
|
266 |
int counter = 0; |
|
267 |
for (ExternalCatalogItem item : externalCatalogItems) { |
|
268 |
statement.clearParameters(); |
|
269 |
statement.setObject(1, item.getId()); |
|
270 |
statement.setString(2, item.getExternalSource().name()); |
|
271 |
statement.setObject(3, item.getLatitude()); |
|
272 |
statement.setObject(4, item.getLongitude()); |
|
273 |
statement.setString(5, item.getLocationPrecision()); |
|
274 |
statement.setObject(6, item.getMaxDate()); |
|
275 |
statement.setObject(7, item.getMinDate()); |
|
276 |
statement.setString(8, item.getTimePeriodKeys()); |
|
277 |
statement.setString(9, item.getPid()); |
|
278 |
statement.setString(10, String.join(",", item.getNames())); |
|
279 |
statement.setString(11, item.getFeatureCode()); |
|
280 |
statement.setString(12, item.getCountry()); |
|
281 |
statement.setObject(13, item.getAccuracy()); |
|
282 |
statement.setObject(14, item.getGeonameId()); |
|
283 |
statement.setObject(15, item.getPleiadesId()); |
|
284 |
statement.setObject(16, item.getOsmId()); |
|
285 |
statement.addBatch(); |
|
286 |
counter++; |
|
287 |
if (counter % BATCH_SIZE == 0 || counter == externalCatalogItems.size()) { |
|
288 |
statement.executeBatch(); |
|
289 |
statement.clearBatch(); |
|
290 |
} |
|
291 |
} |
|
292 |
} catch (Exception e) { |
|
293 |
e.printStackTrace(); |
|
294 |
} |
|
295 |
} |
|
296 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/IExternalCatalogItemService.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import java.util.List; |
|
4 |
|
|
5 |
/** |
|
6 |
* External catalog service interface |
|
7 |
*/ |
|
8 |
public interface IExternalCatalogItemService { |
|
9 |
/** |
|
10 |
* Updates external catalog |
|
11 |
*/ |
|
12 |
void updateCatalog(); |
|
13 |
|
|
14 |
/** |
|
15 |
* Returns external catalog items satisfying given filter |
|
16 |
* |
|
17 |
* @param name name |
|
18 |
* @return list of external catalog items satisfying given filter |
|
19 |
*/ |
|
20 |
List<ExternalCatalogItem> getCatalog(String name, ExternalSource source); |
|
21 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/IExternalCatalogService.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
/** |
|
4 |
* External catalog service interface |
|
5 |
*/ |
|
6 |
public interface IExternalCatalogService { |
|
7 |
/** |
|
8 |
* Updates external catalog |
|
9 |
*/ |
|
10 |
void updateCatalog(); |
|
11 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/external/SetToStringConverter.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.external; |
2 | 2 |
|
3 |
import org.springframework.stereotype.Component; |
|
4 |
|
|
3 | 5 |
import javax.persistence.AttributeConverter; |
4 | 6 |
import java.util.Arrays; |
5 | 7 |
import java.util.HashSet; |
... | ... | |
9 | 11 |
/** |
10 | 12 |
* Class that converts set of strings to string and string to set of strings |
11 | 13 |
*/ |
14 |
@Component |
|
12 | 15 |
public class SetToStringConverter implements AttributeConverter<Set<String>, String> { |
13 | 16 |
/** |
14 | 17 |
* Delimiter for splitting/joining string |
backend/src/main/java/cz/zcu/kiv/backendapi/path/PathController.java | ||
---|---|---|
1 | 1 |
package cz.zcu.kiv.backendapi.path; |
2 | 2 |
|
3 | 3 |
import cz.zcu.kiv.backendapi.catalog.ICatalogItemService; |
4 |
import io.swagger.v3.oas.annotations.Operation; |
|
4 | 5 |
import lombok.RequiredArgsConstructor; |
5 | 6 |
import org.springframework.web.bind.annotation.GetMapping; |
6 | 7 |
import org.springframework.web.bind.annotation.RequestBody; |
... | ... | |
27 | 28 |
* @return path DTO with highlighted text and found catalog items |
28 | 29 |
*/ |
29 | 30 |
@GetMapping("") |
31 |
@Operation(summary = "returns path with highlighted text and found catalog items based on given text") |
|
30 | 32 |
public PathDto getPath(@RequestBody PathDto pathDto) { |
31 | 33 |
return catalogItemService.getPath(pathDto.getText()); |
32 | 34 |
} |
backend/src/main/java/cz/zcu/kiv/backendapi/security/SecurityConfig.java | ||
---|---|---|
62 | 62 |
PERMITTED_ENDPOINTS.put("/v3/api-docs/swagger-config", HttpMethod.GET); |
63 | 63 |
PERMITTED_ENDPOINTS.put("/catalog-items", HttpMethod.GET); |
64 | 64 |
PERMITTED_ENDPOINTS.put("/catalog-items/**", HttpMethod.GET); |
65 |
PERMITTED_ENDPOINTS.put("/external-catalog-items", HttpMethod.POST); //TODO delete
|
|
65 |
PERMITTED_ENDPOINTS.put("/title-page", HttpMethod.GET);
|
|
66 | 66 |
} |
67 | 67 |
|
68 | 68 |
/** |
... | ... | |
84 | 84 |
.authorizeRequests() |
85 | 85 |
.antMatchers(HttpMethod.GET, PERMITTED_ENDPOINTS.keySet().stream().filter(k -> PERMITTED_ENDPOINTS.get(k).equals(HttpMethod.GET)).toArray(String[]::new)).permitAll() |
86 | 86 |
.antMatchers(HttpMethod.POST, "/login").permitAll() |
87 |
.antMatchers(HttpMethod.POST, "/external-catalog-items").permitAll() //TODO delete
|
|
87 |
.antMatchers("/external-catalog-items").hasRole(Role.ADMIN.name())
|
|
88 | 88 |
.antMatchers(HttpMethod.PATCH, "/users/*/permissions", "/users/*/password").hasRole(Role.ADMIN.name()) |
89 | 89 |
.antMatchers(HttpMethod.DELETE, "/users/**").hasRole(Role.ADMIN.name()) |
90 | 90 |
.antMatchers(HttpMethod.GET, "/users").hasRole(Role.ADMIN.name()) |
backend/src/test/java/cz/zcu/kiv/backendapi/catalog/CatalogItemServiceImplTest.java | ||
---|---|---|
88 | 88 |
// given |
89 | 89 |
CatalogItemDto catalogItemDto = new CatalogItemDto(); |
90 | 90 |
catalogItemDto.setName("name"); |
91 |
catalogItemDto.setBibliography(Set.of("bibl"));
|
|
92 |
catalogItemDto.setTypes(Set.of("type"));
|
|
93 |
catalogItemDto.setAlternativeNames(Set.of("altName"));
|
|
94 |
catalogItemDto.setCountries(Set.of("country"));
|
|
95 |
catalogItemDto.setWrittenForms(Set.of("written"));
|
|
91 |
catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toSet()));
|
|
92 |
catalogItemDto.setTypes(Stream.of("type").collect(Collectors.toSet()));
|
|
93 |
catalogItemDto.setAlternativeNames(Stream.of("altName").collect(Collectors.toSet()));
|
|
94 |
catalogItemDto.setCountries(Stream.of("country").collect(Collectors.toSet()));
|
|
95 |
catalogItemDto.setWrittenForms(Stream.of("written").collect(Collectors.toSet()));
|
|
96 | 96 |
catalogItemDto.setCertainty(0); |
97 | 97 |
catalogItemDto.setLatitude(0.1); |
98 | 98 |
catalogItemDto.setLongitude(0.2); |
... | ... | |
102 | 102 |
|
103 | 103 |
CatalogItem catalogItem = new CatalogItem(); |
104 | 104 |
catalogItem.setName("name"); |
105 |
catalogItem.setBibliography(Set.of(new Bibliography("bibl", catalogItem)));
|
|
106 |
catalogItem.setTypes(Set.of(type));
|
|
107 |
catalogItem.setAlternativeNames(Set.of(new AlternativeName("altName", catalogItem)));
|
|
108 |
catalogItem.setCountries(Set.of(new Country("country", catalogItem)));
|
|
109 |
catalogItem.setWrittenForms(Set.of(new WrittenForm("written", catalogItem)));
|
|
105 |
catalogItem.setBibliography(Stream.of(new Bibliography("bibl", catalogItem)).collect(Collectors.toSet()));
|
|
106 |
catalogItem.setTypes(Stream.of(type).collect(Collectors.toSet()));
|
|
107 |
catalogItem.setAlternativeNames(Stream.of(new AlternativeName("altName", catalogItem), new AlternativeName("name", catalogItem)).collect(Collectors.toSet()));
|
|
108 |
catalogItem.setCountries(Stream.of(new Country("country", catalogItem)).collect(Collectors.toSet()));
|
|
109 |
catalogItem.setWrittenForms(Stream.of(new WrittenForm("written", catalogItem)).collect(Collectors.toSet()));
|
|
110 | 110 |
catalogItem.setCertainty(0); |
111 | 111 |
catalogItem.setLatitude(0.1); |
112 | 112 |
catalogItem.setLongitude(0.2); |
... | ... | |
177 | 177 |
|
178 | 178 |
CatalogItemDto catalogItemDto = new CatalogItemDto(); |
179 | 179 |
catalogItemDto.setName("name"); |
180 |
catalogItemDto.setBibliography(Set.of("bibl"));
|
|
181 |
catalogItemDto.setTypes(Set.of("type"));
|
|
182 |
catalogItemDto.setAlternativeNames(Set.of("altName"));
|
|
183 |
catalogItemDto.setCountries(Set.of("country"));
|
|
184 |
catalogItemDto.setWrittenForms(Set.of("written"));
|
|
180 |
catalogItemDto.setBibliography(Stream.of("bibl").collect(Collectors.toSet()));
|
|
181 |
catalogItemDto.setTypes(Stream.of("type").collect(Collectors.toSet()));
|
|
182 |
catalogItemDto.setAlternativeNames(Stream.of("altName").collect(Collectors.toSet()));
|
|
183 |
catalogItemDto.setCountries(Stream.of("country").collect(Collectors.toSet()));
|
|
184 |
catalogItemDto.setWrittenForms(Stream.of("written").collect(Collectors.toSet()));
|
|
185 | 185 |
catalogItemDto.setCertainty(0); |
186 | 186 |
catalogItemDto.setLatitude(0.1); |
187 | 187 |
catalogItemDto.setLongitude(0.2); |
... | ... | |
237 | 237 |
assertThat(capturedCatalogItem.getLongitude()).isEqualTo(catalogItem.getLongitude()); |
238 | 238 |
assertThat(capturedCatalogItem.getDescription()).isEqualTo(catalogItem.getDescription()); |
239 | 239 |
assertThat(capturedCatalogItem.getTypes().stream().map(Type::getType).collect(Collectors.toSet())).isEqualTo(catalogItem.getTypes().stream().map(Type::getType).collect(Collectors.toSet())); |
240 |
assertThat(capturedCatalogItem.getAlternativeNames().stream().map(AlternativeName::getName).collect(Collectors.toSet())).isEqualTo(catalogItem.getAlternativeNames().stream().map(AlternativeName::getName).collect(Collectors.toSet())); |
|
240 |
Set<String> alternativeNamesEntity = catalogItem.getAlternativeNames().stream().map(AlternativeName::getName).collect(Collectors.toSet()); |
|
241 |
alternativeNamesEntity.add(catalogItem.getName()); |
|
242 |
assertThat(capturedCatalogItem.getAlternativeNames().stream().map(AlternativeName::getName).collect(Collectors.toSet())).isEqualTo(alternativeNamesEntity); |
|
241 | 243 |
assertThat(capturedCatalogItem.getCountries().stream().map(Country::getName).collect(Collectors.toSet())).isEqualTo(catalogItem.getCountries().stream().map(Country::getName).collect(Collectors.toSet())); |
242 | 244 |
assertThat(capturedCatalogItem.getBibliography().stream().map(Bibliography::getSource).collect(Collectors.toSet())).isEqualTo(catalogItem.getBibliography().stream().map(Bibliography::getSource).collect(Collectors.toSet())); |
243 | 245 |
assertThat(capturedCatalogItem.getWrittenForms().stream().map(WrittenForm::getForm).collect(Collectors.toSet())).isEqualTo(catalogItem.getWrittenForms().stream().map(WrittenForm::getForm).collect(Collectors.toSet())); |
backend/src/test/java/cz/zcu/kiv/backendapi/external/ExternalCatalogItemItemServiceImplTest.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import com.zaxxer.hikari.HikariDataSource; |
|
4 |
import org.junit.jupiter.api.BeforeEach; |
|
5 |
import org.junit.jupiter.api.Test; |
|
6 |
import org.junit.jupiter.api.extension.ExtendWith; |
|
7 |
import org.mockito.Mock; |
|
8 |
import org.mockito.junit.jupiter.MockitoExtension; |
|
9 |
|
|
10 |
import java.util.List; |
|
11 |
import java.util.Set; |
|
12 |
import java.util.UUID; |
|
13 |
|
|
14 |
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; |
|
15 |
import static org.junit.jupiter.api.Assertions.assertTrue; |
|
16 |
import static org.mockito.BDDMockito.given; |
|
17 |
import static org.mockito.Mockito.verify; |
|
18 |
|
|
19 |
@ExtendWith(MockitoExtension.class) |
|
20 |
class ExternalCatalogItemItemServiceImplTest { |
|
21 |
|
|
22 |
@Mock |
|
23 |
private ExternalCatalogItemRepository externalCatalogItemRepository; |
|
24 |
|
|
25 |
@Mock |
|
26 |
private HikariDataSource hikariDataSource; |
|
27 |
|
|
28 |
@Mock |
|
29 |
private SetToStringConverter setToStringConverter; |
|
30 |
|
|
31 |
private ExternalCatalogItemItemServiceImpl underTest; |
|
32 |
|
|
33 |
@BeforeEach |
|
34 |
void setUp() { |
|
35 |
underTest = new ExternalCatalogItemItemServiceImpl(externalCatalogItemRepository, hikariDataSource, setToStringConverter); |
|
36 |
} |
|
37 |
|
|
38 |
@Test |
|
39 |
void getCatalog() { |
|
40 |
// given |
|
41 |
ExternalCatalogItem catalogItem1 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("first", "NAME"), null, null, null, null, null, null); |
|
42 |
ExternalCatalogItem catalogItem2 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("second", "name"), null, null, null, null, null, null); |
|
43 |
ExternalCatalogItem catalogItem3 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("fourth", "nane"), null, null, null, null, null, null); |
|
44 |
String name = "na?*"; |
|
45 |
ExternalSource source = ExternalSource.PLEIADES; |
|
46 |
given(externalCatalogItemRepository.getFilteredExternalCatalog("%na_%%", source.name())).willReturn(List.of(catalogItem1, catalogItem2, catalogItem3)); |
|
47 |
|
|
48 |
// when |
|
49 |
List<ExternalCatalogItem> result = underTest.getCatalog(name, source); |
|
50 |
|
|
51 |
// then |
|
52 |
verify(externalCatalogItemRepository).getFilteredExternalCatalog("%na_%%", source.name()); |
|
53 |
assertThat(result.size()).isEqualTo(3); |
|
54 |
assertTrue(result.contains(catalogItem1)); |
|
55 |
assertTrue(result.contains(catalogItem2)); |
|
56 |
assertTrue(result.contains(catalogItem3)); |
|
57 |
} |
|
58 |
} |
backend/src/test/java/cz/zcu/kiv/backendapi/external/ExternalCatalogItemRepositoryTest.java | ||
---|---|---|
1 |
package cz.zcu.kiv.backendapi.external; |
|
2 |
|
|
3 |
import org.junit.jupiter.api.AfterEach; |
|
4 |
import org.junit.jupiter.api.BeforeEach; |
|
5 |
import org.junit.jupiter.api.Test; |
|
6 |
import org.springframework.beans.factory.annotation.Autowired; |
|
7 |
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; |
|
8 |
|
|
9 |
import java.util.List; |
|
10 |
import java.util.Set; |
|
11 |
import java.util.UUID; |
|
12 |
|
|
13 |
import static org.assertj.core.api.Assertions.assertThat; |
|
14 |
import static org.junit.jupiter.api.Assertions.assertTrue; |
|
15 |
|
|
16 |
@DataJpaTest |
|
17 |
class ExternalCatalogItemRepositoryTest { |
|
18 |
|
|
19 |
@Autowired |
|
20 |
private ExternalCatalogItemRepository underTest; |
|
21 |
|
|
22 |
private ExternalCatalogItem catalogItem1; |
|
23 |
private ExternalCatalogItem catalogItem2; |
|
24 |
private ExternalCatalogItem catalogItem3; |
|
25 |
private ExternalCatalogItem catalogItem4; |
|
26 |
|
|
27 |
private ExternalCatalogItem catalogItem5; |
|
28 |
private ExternalCatalogItem catalogItem6; |
|
29 |
|
|
30 |
private ExternalCatalogItem catalogItem7; |
|
31 |
|
|
32 |
@BeforeEach |
|
33 |
void setUp() { |
|
34 |
catalogItem1 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("first", "NAME"), null, null, null, null, null, null); |
|
35 |
catalogItem2 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("second", "name"), null, null, null, null, null, null); |
|
36 |
catalogItem3 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.CIGS, 10.0, 10.0, null, null, null, null, null, Set.of("third", "NAME"), null, null, null, null, null, null); |
|
37 |
catalogItem4 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.PLEIADES, 10.0, 10.0, null, null, null, null, null, Set.of("fourth", "nane"), null, null, null, null, null, null); |
|
38 |
catalogItem5 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.GEONAMES, 10.0, 10.0, null, null, null, null, null, Set.of("fifthName", "Achala"), null, null, null, null, null, null); |
|
39 |
catalogItem6 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.GEONAMES, 10.0, 10.0, null, null, null, null, null, Set.of("fifthMama", "Bafala"), null, null, null, null, null, null); |
|
40 |
catalogItem7 = new ExternalCatalogItem(UUID.randomUUID(), ExternalSource.CIGS, 10.0, 10.0, null, null, null, null, null, Set.of("seventhName", "hello"), null, null, null, null, null, null); |
|
41 |
underTest.saveAll(List.of(catalogItem1, catalogItem2, catalogItem3, catalogItem4, catalogItem5, catalogItem6, catalogItem7)); |
|
42 |
} |
|
43 |
|
|
44 |
@AfterEach |
|
45 |
void tearDown() { |
|
46 |
underTest.deleteAll(); |
|
47 |
} |
|
48 |
|
|
49 |
@Test |
|
50 |
void getFilteredExternalCatalog() { |
|
51 |
// given |
|
52 |
// when |
|
53 |
List<ExternalCatalogItem> result = underTest.getFilteredExternalCatalog("%name%", ExternalSource.PLEIADES.name()); |
|
54 |
|
|
55 |
// then |
|
56 |
assertThat(result.size()).isEqualTo(2); |
|
57 |
assertTrue(result.contains(catalogItem1)); |
|
58 |
assertTrue(result.contains(catalogItem2)); |
|
59 |
} |
|
60 |
|
|
61 |
@Test |
|
62 |
void getFilteredExternalCatalogWildcardsCharacter() { |
|
63 |
// given |
|
64 |
// when |
|
65 |
List<ExternalCatalogItem> result = underTest.getFilteredExternalCatalog("%na_e%", ExternalSource.PLEIADES.name()); |
|
66 |
|
|
67 |
// then |
|
68 |
assertThat(result.size()).isEqualTo(3); |
|
69 |
assertTrue(result.contains(catalogItem1)); |
|
70 |
assertTrue(result.contains(catalogItem2)); |
|
71 |
assertTrue(result.contains(catalogItem4)); |
|
72 |
} |
|
73 |
|
|
74 |
@Test |
|
75 |
void getFilteredExternalCatalogWildcardsCharacters() { |
|
76 |
// given |
|
77 |
// when |
|
78 |
List<ExternalCatalogItem> result = underTest.getFilteredExternalCatalog("%fifth%%", ExternalSource.GEONAMES.name()); |
|
79 |
|
|
80 |
// then |
|
81 |
assertThat(result.size()).isEqualTo(2); |
|
82 |
assertTrue(result.contains(catalogItem5)); |
|
83 |
assertTrue(result.contains(catalogItem6)); |
|
84 |
} |
|
85 |
|
|
86 |
@Test |
|
87 |
void getFilteredExternalCatalogAllSource() { |
|
88 |
// given |
|
89 |
// when |
|
90 |
List<ExternalCatalogItem> result = underTest.getFilteredExternalCatalog("%%%", ExternalSource.CIGS.name()); |
|
91 |
|
|
92 |
// then |
|
93 |
assertThat(result.size()).isEqualTo(2); |
|
94 |
assertTrue(result.contains(catalogItem3)); |
|
95 |
assertTrue(result.contains(catalogItem7)); |
|
96 |
} |
|
97 |
} |
Také k dispozici: Unified diff
Added controller and some tests for external catalog
re #9624