Projekt

Obecné

Profil

Stáhnout (13.4 KB) Statistiky
| Větev: | Tag: | Revize:
1
package cz.zcu.kiv.backendapi.catalog;
2

    
3
import cz.zcu.kiv.backendapi.alternativename.CatalogItemName;
4
import cz.zcu.kiv.backendapi.bibliography.Bibliography;
5
import cz.zcu.kiv.backendapi.country.Country;
6
import cz.zcu.kiv.backendapi.exception.ApiRequestException;
7
import cz.zcu.kiv.backendapi.path.PathDto;
8
import cz.zcu.kiv.backendapi.type.ITypeService;
9
import cz.zcu.kiv.backendapi.type.Type;
10
import cz.zcu.kiv.backendapi.writtenform.WrittenForm;
11
import lombok.RequiredArgsConstructor;
12
import lombok.extern.slf4j.Slf4j;
13
import org.apache.commons.lang3.StringUtils;
14
import org.springframework.http.HttpStatus;
15
import org.springframework.stereotype.Service;
16
import org.springframework.transaction.annotation.Transactional;
17

    
18
import java.util.*;
19
import java.util.concurrent.atomic.AtomicInteger;
20
import java.util.function.Predicate;
21
import java.util.regex.Matcher;
22
import java.util.regex.Pattern;
23
import java.util.stream.Collectors;
24

    
25
/**
26
 * Catalog item service implementation
27
 */
28
@Service
29
@Transactional
30
@RequiredArgsConstructor
31
@Slf4j
32
public class CatalogItemServiceImpl implements ICatalogItemService {
33
    /**
34
     * Regex for one arbitrary character in string
35
     */
36
    private static final String WILDCARD_CHARACTER_REGEX = "\\?";
37

    
38
    /**
39
     * Regex for one arbitrary character in string used in Java
40
     */
41
    private static final String WILDCARD_CHARACTER_REGEX_JAVA = ".";
42

    
43
    /**
44
     * Regex for any number of arbitrary characters in string
45
     */
46
    private static final String WILDCARD_CHARACTERS_REGEX = "\\*";
47

    
48
    /**
49
     * Regex for any number of arbitrary characters in string used in Java
50
     */
51
    private static final String WILDCARD_CHARACTERS_REGEX_JAVA = ".*";
52

    
53
    /**
54
     * Regex for finding punctuation at the start of word
55
     */
56
    private static final String START_PUNCTUATION_REGEX = "^[\\p{Punct}\\p{IsPunctuation}]+";
57

    
58
    /**
59
     * Regex for finding punctuation at the end of word
60
     */
61
    private static final String END_PUNCTUATION_REGEX = "[\\p{Punct}\\p{IsPunctuation}]+$";
62

    
63
    /**
64
     * Pattern for finding punctuation at the start of word
65
     */
66
    private static final Pattern START_PUNCTUATION_PATTERN = Pattern.compile(START_PUNCTUATION_REGEX);
67

    
68
    /**
69
     * Pattern for finding punctuation at the end of word
70
     */
71
    private static final Pattern END_PUNCTUATION_PATTERN = Pattern.compile(END_PUNCTUATION_REGEX);
72

    
73
    /**
74
     * Message for exception when catalog item is not found by id
75
     */
76
    private static final String CATALOG_ITEM_NOT_FOUND = "Catalog item not found";
77

    
78

    
79
    /**
80
     * Catalog repository
81
     */
82
    private final CatalogItemRepository catalogItemRepository;
83

    
84
    /**
85
     * Type service
86
     */
87
    private final ITypeService typeService;
88

    
89
    @Override
90
    public void saveCatalogItems(List<CatalogItemDto> catalogItemDtoList) {
91
        log.info("Saving catalog");
92
        catalogItemDtoList.forEach(this::saveCatalogItem);
93
        log.info("Catalog saved");
94
    }
95

    
96
    @Override
97
    public void saveCatalogItem(CatalogItemDto catalogItemDto) {
98
        log.info("Saving catalog item");
99
        CatalogItem catalogItem;
100
        Optional<CatalogItem> optionalCatalogItem;
101
        if (catalogItemDto.getId() != null && (optionalCatalogItem = catalogItemRepository.findById(catalogItemDto.getId())).isPresent()) {
102
            catalogItem = optionalCatalogItem.get();
103
        } else {
104
            catalogItem = new CatalogItem();
105
        }
106
        convertDtoToEntity(catalogItemDto, catalogItem);
107
        saveCatalogEntity(catalogItem);
108
        log.info("Catalog item saved");
109
    }
110

    
111
    @Override
112
    public void deleteCatalogItem(UUID id) {
113
        if (!catalogItemRepository.existsById(id)) {
114
            log.error(CATALOG_ITEM_NOT_FOUND);
115
            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
116
        }
117
        catalogItemRepository.deleteById(id);
118
        log.info("Catalog item deleted");
119
    }
120

    
121
    @Override
122
    public CatalogItemDto getCatalogItem(UUID id) {
123
        CatalogItem catalogItem = catalogItemRepository.findById(id).orElseThrow(() -> {
124
            log.error(CATALOG_ITEM_NOT_FOUND);
125
            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
126
        });
127

    
128
        return convertEntityToDto(catalogItem);
129
    }
130

    
131
    @Override
132
    public PathDto getPath(String text) {
133
        log.info("Searching path");
134
        PathDto pathDto = new PathDto();
135
        StringBuilder highlightedText = new StringBuilder();
136
        List<List<CatalogItemDto>> foundCatalogItems = new ArrayList<>();
137

    
138
        Set<String> types = typeService.getAllTypesAsString();
139

    
140
        List<CatalogItem> catalog = catalogItemRepository.findAll();
141
        Map<String, List<CatalogItem>> nameToCatalogItemMap = new HashMap<>();
142
        for (CatalogItem catalogItem : catalog) {
143
            for (CatalogItemName name : catalogItem.getAllNames()) {
144
                if (!nameToCatalogItemMap.containsKey(name.getName())) {
145
                    nameToCatalogItemMap.put(name.getName(), new ArrayList<>());
146
                }
147
                nameToCatalogItemMap.get(name.getName()).add(catalogItem);
148
            }
149
        }
150

    
151
        String[] tokens = text.split("((?<=\\s)|(?=\\s+))");
152
        for (String token : tokens) {
153
            if (StringUtils.isBlank(token) || token.matches(START_PUNCTUATION_REGEX)) {
154
                highlightedText.append(token);
155
                continue;
156
            }
157

    
158
            Matcher matcherStart = START_PUNCTUATION_PATTERN.matcher(token);
159
            Matcher matcherEnd = END_PUNCTUATION_PATTERN.matcher(token);
160
            String prefix = "";
161
            String suffix = "";
162
            String textToFind;
163
            int startTextIndex = 0;
164
            int endTextIndex = token.length();
165

    
166
            if (matcherStart.find()) {
167
                int start = matcherStart.start();
168
                startTextIndex = matcherStart.end();
169
                prefix = token.substring(start, startTextIndex);
170
            }
171

    
172
            if (matcherEnd.find()) {
173
                endTextIndex = matcherEnd.start();
174
                int end = matcherEnd.end();
175
                suffix = token.substring(endTextIndex, end);
176
            }
177

    
178
            textToFind = token.substring(startTextIndex, endTextIndex);
179

    
180
            if (types.contains(textToFind)) {
181
                textToFind = "<b>" + textToFind + "</b>";
182
            } else {
183
                if (nameToCatalogItemMap.containsKey(textToFind)) {
184
                    List<CatalogItem> foundItems = nameToCatalogItemMap.get(textToFind);
185
                    if (foundItems.stream().anyMatch(c -> c.getLatitude() != null && c.getLongitude() != null)) {
186
                        textToFind = "<span style='color:green'>" + textToFind + "</span>";
187
                    } else {
188
                        textToFind = "<span style='color:red'>" + textToFind + "</span>";
189
                    }
190
                    foundCatalogItems.add(foundItems.stream().map(this::convertEntityToDto).collect(Collectors.toList()));
191
                }
192
            }
193
            highlightedText.append(prefix).append(textToFind).append(suffix);
194
        }
195

    
196
        pathDto.setText(highlightedText.toString());
197
        pathDto.setFoundCatalogItems(foundCatalogItems);
198
        log.info("Path searched");
199
        return pathDto;
200
    }
201

    
202
    @Override
203
    public List<CatalogItemDto> getCatalog(String name, String country, String type, String writtenForm) {
204
        log.info("Retrieving catalog");
205
        String finalName = name.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
206
        String finalCountry = country.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
207
        String finalType = type.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
208
        String finalWrittenForm = writtenForm.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
209

    
210
        Pattern patternName = Pattern.compile(finalName, Pattern.CASE_INSENSITIVE);
211
        Pattern patternCountry = Pattern.compile(finalCountry, Pattern.CASE_INSENSITIVE);
212
        Pattern patternType = Pattern.compile(finalType, Pattern.CASE_INSENSITIVE);
213
        Pattern patternWrittenForm = Pattern.compile(finalWrittenForm, Pattern.CASE_INSENSITIVE);
214

    
215
        List<CatalogItem> catalogItems = catalogItemRepository.findAll();
216

    
217
        Predicate<CatalogItem> predicateType = i -> finalType.equals("") || i.getTypes().stream().anyMatch(t -> patternType.matcher(t.getType()).matches());
218
        Predicate<CatalogItem> predicateCountry = i -> finalCountry.equals("") || i.getCountries().stream().anyMatch(t -> patternCountry.matcher(t.getName()).matches());
219
        Predicate<CatalogItem> predicateName = i -> finalName.equals("") || patternName.matcher(i.getName()).matches() || i.getAllNames().stream().anyMatch(t -> patternName.matcher(t.getName()).matches());
220
        Predicate<CatalogItem> predicateWrittenForm = i -> finalWrittenForm.equals("") || i.getWrittenForms().stream().anyMatch(t -> patternWrittenForm.matcher(t.getForm()).matches());
221

    
222
        catalogItems = catalogItems.stream().filter(predicateName.and(predicateCountry).and(predicateType).and(predicateWrittenForm)).collect(Collectors.toList());
223
        return catalogItems.stream().map(this::convertEntityToDto).collect(Collectors.toList());
224
    }
225

    
226
    /**
227
     * Saves catalog item to database
228
     *
229
     * @param catalogItem catalog item
230
     */
231
    private void saveCatalogEntity(CatalogItem catalogItem) {
232
        for (Type type : catalogItem.getTypes()) {
233
            if (typeService.getTypeByName(type.getType()).isEmpty()) {
234
                typeService.saveType(type);
235
            }
236
        }
237
        catalogItemRepository.save(catalogItem);
238
    }
239

    
240
    /**
241
     * Converts catalog item DTO to catalog item entity
242
     *
243
     * @param catalogItemDto catalog item DTO
244
     * @param catalogItem    catalog item entity
245
     */
246
    private void convertDtoToEntity(CatalogItemDto catalogItemDto, CatalogItem catalogItem) {
247
        AtomicInteger counter = new AtomicInteger(1);
248

    
249
        catalogItem.setName(catalogItemDto.getName());
250
        catalogItem.setCertainty(catalogItemDto.getCertainty());
251
        catalogItem.setLatitude(catalogItemDto.getLatitude());
252
        catalogItem.setLongitude(catalogItemDto.getLongitude());
253

    
254
        catalogItem.getBibliography().clear();
255
        catalogItem.getBibliography().addAll(catalogItemDto.getBibliography()
256
                .stream().map(s -> new Bibliography(s, catalogItem, counter.getAndIncrement())).collect(Collectors.toCollection(LinkedHashSet::new)));
257

    
258
        catalogItem.getTypes().clear();
259
        catalogItem.getTypes().addAll(catalogItemDto.getTypes()
260
                .stream().map(Type::new).collect(Collectors.toCollection(LinkedHashSet::new)));
261

    
262
        catalogItem.getCountries().clear();
263
        counter.set(1);
264
        catalogItem.getCountries().addAll(catalogItemDto.getCountries()
265
                .stream().map(s -> new Country(s, catalogItem, counter.getAndIncrement())).collect(Collectors.toCollection(LinkedHashSet::new)));
266

    
267
        catalogItem.getAllNames().clear();
268
        counter.set(1);
269
        Set<String> allNames = new LinkedHashSet<>();
270
        allNames.add(catalogItemDto.getName());
271
        allNames.addAll(catalogItemDto.getAllNames());
272
        catalogItem.getAllNames().addAll(allNames
273
                .stream().map(s -> new CatalogItemName(s, catalogItem, counter.getAndIncrement())).collect(Collectors.toCollection(LinkedHashSet::new)));
274

    
275
        catalogItem.getWrittenForms().clear();
276
        counter.set(1);
277
        catalogItem.getWrittenForms().addAll(catalogItemDto.getWrittenForms()
278
                .stream().map(s -> new WrittenForm(s, catalogItem, counter.getAndIncrement())).collect(Collectors.toCollection(LinkedHashSet::new)));
279

    
280
        catalogItem.setDescription(catalogItemDto.getDescription());
281
    }
282

    
283
    /**
284
     * Converts catalog item entity to catalog item DTO
285
     *
286
     * @param catalogItem catalog item entity
287
     * @return catalog item DTO
288
     */
289
    private CatalogItemDto convertEntityToDto(CatalogItem catalogItem) {
290
        CatalogItemDto catalogItemDto = new CatalogItemDto();
291
        catalogItemDto.setId(catalogItem.getId());
292
        catalogItemDto.setName(catalogItem.getName());
293
        catalogItemDto.setLatitude(catalogItem.getLatitude());
294
        catalogItemDto.setLongitude(catalogItem.getLongitude());
295
        catalogItemDto.setCertainty(catalogItem.getCertainty());
296
        catalogItemDto.setBibliography(catalogItem.getBibliography()
297
                .stream().map(Bibliography::getSource).collect(Collectors.toCollection(LinkedHashSet::new)));
298
        catalogItemDto.setTypes(catalogItem.getTypes()
299
                .stream().map(Type::getType).collect(Collectors.toCollection(LinkedHashSet::new)));
300
        catalogItemDto.setCountries(catalogItem.getCountries()
301
                .stream().map(Country::getName).collect(Collectors.toCollection(LinkedHashSet::new)));
302
        catalogItemDto.setAllNames(catalogItem.getAllNames()
303
                .stream().map(CatalogItemName::getName).collect(Collectors.toCollection(LinkedHashSet::new)));
304
        catalogItemDto.setWrittenForms(catalogItem.getWrittenForms()
305
                .stream().map(WrittenForm::getForm).collect(Collectors.toCollection(LinkedHashSet::new)));
306
        catalogItemDto.setDescription(catalogItem.getDescription());
307
        return catalogItemDto;
308
    }
309

    
310
}
(5-5/6)