Projekt

Obecné

Profil

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

    
3
import cz.zcu.kiv.backendapi.alternativename.AlternativeName;
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.springframework.http.HttpStatus;
14
import org.springframework.stereotype.Service;
15
import org.springframework.transaction.annotation.Transactional;
16

    
17
import java.util.*;
18
import java.util.function.Predicate;
19
import java.util.regex.Matcher;
20
import java.util.regex.Pattern;
21
import java.util.stream.Collectors;
22

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

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

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

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

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

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

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

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

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

    
76
    /**
77
     * Threshold for comparing doubles
78
     */
79
    private static final double DOUBLE_THRESHOLD = 0.001;
80

    
81
    /**
82
     * Catalog repository
83
     */
84
    private final CatalogItemRepository catalogItemRepository;
85

    
86
    /**
87
     * Type service
88
     */
89
    private final ITypeService typeService;
90

    
91
    @Override
92
    public void saveCatalog(List<CatalogItem> catalogItems) {
93
        log.info("Saving catalog");
94
        catalogItems.forEach(this::saveCatalogEntity);
95
    }
96

    
97
    @Override
98
    public void saveCatalogItem(CatalogItemDto catalogItemDto) {
99
        log.info("Saving catalog item");
100
        CatalogItem catalogItem = new CatalogItem();
101
        convertDtoToEntity(catalogItemDto, catalogItem);
102
        saveCatalogEntity(catalogItem);
103
    }
104

    
105
    @Override
106
    public void updateCatalogItem(UUID id, CatalogItemDto catalogItemDto) {
107
        CatalogItem catalogItem = catalogItemRepository.findById(id).orElseThrow(() -> {
108
            log.error(CATALOG_ITEM_NOT_FOUND);
109
            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
110
        });
111
        convertDtoToEntity(catalogItemDto, catalogItem);
112
        saveCatalogEntity(catalogItem);
113
        log.info("Catalog item updated");
114
    }
115

    
116
    @Override
117
    public void deleteCatalogItem(UUID id) {
118
        if (!catalogItemRepository.existsById(id)) {
119
            log.error(CATALOG_ITEM_NOT_FOUND);
120
            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
121
        }
122
        catalogItemRepository.deleteById(id);
123
        log.info("Catalog item deleted");
124
    }
125

    
126
    private final Map<String, AlternativeName> map = new HashMap<>();
127

    
128
    @Override
129
    public CatalogItemDto getCatalogItem(UUID id) {
130
        CatalogItem catalogItem = catalogItemRepository.findById(id).orElseThrow(() -> {
131
            log.error(CATALOG_ITEM_NOT_FOUND);
132
            throw new ApiRequestException(CATALOG_ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
133
        });
134

    
135
        return convertEntityToDto(catalogItem);
136
    }
137

    
138
    @Override
139
    public PathDto getPath(String text) {
140
        PathDto pathDto = new PathDto();
141
        StringBuilder highlightedText = new StringBuilder();
142
        List<List<CatalogItemDto>> foundCatalogItems = new ArrayList<>();
143

    
144
        Set<String> types = typeService.getAllTypesAsString();
145

    
146
        String[] tokens = text.split("\\s+");
147
        for (String token : tokens) {
148
            Matcher matcherStart = START_PUNCTUATION_PATTERN.matcher(token);
149
            Matcher matcherEnd = END_PUNCTUATION_PATTERN.matcher(token);
150
            String prefix = "";
151
            String suffix = "";
152
            String textToFind;
153
            int startTextIndex = 0;
154
            int endTextIndex = token.length();
155

    
156
            if (matcherStart.find()) {
157
                int start = matcherStart.start();
158
                startTextIndex = matcherStart.end();
159
                prefix = token.substring(start, startTextIndex);
160
            }
161
            if (matcherEnd.find()) {
162
                endTextIndex = matcherEnd.start();
163
                int end = matcherEnd.end();
164
                suffix = token.substring(endTextIndex, end);
165
            }
166

    
167
            textToFind = token.substring(startTextIndex, endTextIndex);
168

    
169
            if (types.contains(textToFind)) {
170
                textToFind = "<b>" + textToFind + "</b>";
171
            } else {
172
                List<CatalogItem> foundItems = catalogItemRepository.getItemsByName(textToFind);
173
                if (!foundItems.isEmpty()) {
174
                    if (foundItems.stream().anyMatch(c -> Math.abs(c.getLatitude()) > DOUBLE_THRESHOLD && Math.abs(c.getLongitude()) > DOUBLE_THRESHOLD)) {
175
                        textToFind = "<span style='color:green'>" + textToFind + "</span>";
176
                    } else {
177
                        textToFind = "<span style='color:red'>" + textToFind + "</span>";
178
                    }
179
                    foundCatalogItems.add(foundItems.stream().map(this::convertEntityToDto).collect(Collectors.toList()));
180
                }
181
            }
182
            highlightedText.append(prefix).append(textToFind).append(suffix).append(" ");
183
        }
184
        highlightedText.setLength(highlightedText.length() - 1);
185

    
186
        pathDto.setText(highlightedText.toString());
187
        pathDto.setFoundCatalogItems(foundCatalogItems);
188
        return pathDto;
189
    }
190

    
191
    @Override
192
    public List<CatalogItemDto> getCatalog(String name, String country, String type, String writtenForm) {
193
        log.info("Retrieving catalog");
194
        String finalName = name.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
195
        String finalCountry = country.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
196
        String finalType = type.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
197
        String finalWrittenForm = writtenForm.replaceAll(WILDCARD_CHARACTER_REGEX, WILDCARD_CHARACTER_REGEX_JAVA).replaceAll(WILDCARD_CHARACTERS_REGEX, WILDCARD_CHARACTERS_REGEX_JAVA);
198

    
199
        Pattern patternName = Pattern.compile(finalName, Pattern.CASE_INSENSITIVE);
200
        Pattern patternCountry = Pattern.compile(finalCountry, Pattern.CASE_INSENSITIVE);
201
        Pattern patternType = Pattern.compile(finalType, Pattern.CASE_INSENSITIVE);
202
        Pattern patternWrittenForm = Pattern.compile(finalWrittenForm, Pattern.CASE_INSENSITIVE);
203

    
204
        List<CatalogItem> catalogItems = catalogItemRepository.findAll();
205

    
206
        Predicate<CatalogItem> predicateType = i -> finalType.equals("") || i.getTypes().stream().anyMatch(t -> patternType.matcher(t.getType()).matches());
207
        Predicate<CatalogItem> predicateCountry = i -> finalCountry.equals("") || i.getCountries().stream().anyMatch(t -> patternCountry.matcher(t.getName()).matches());
208
        Predicate<CatalogItem> predicateName = i -> finalName.equals("") || patternName.matcher(i.getName()).matches() || i.getAlternativeNames().stream().anyMatch(t -> patternName.matcher(t.getName()).matches());
209
        Predicate<CatalogItem> predicateWrittenForm = i -> finalWrittenForm.equals("") || i.getWrittenForms().stream().anyMatch(t -> patternWrittenForm.matcher(t.getForm()).matches());
210

    
211
        catalogItems = catalogItems.stream().filter(predicateName.and(predicateCountry).and(predicateType).and(predicateWrittenForm)).collect(Collectors.toList());
212
        return catalogItems.stream().map(this::convertEntityToDto).collect(Collectors.toList());
213
    }
214

    
215
    /**
216
     * Saves catalog entity to database
217
     *
218
     * @param catalogItem catalog entity
219
     */
220
    private void saveCatalogEntity(CatalogItem catalogItem) {
221
        for (Type type : catalogItem.getTypes()) {
222
            if (typeService.getTypeByName(type.getType()).isEmpty()) {
223
                typeService.saveType(type);
224
            }
225
        }
226
        catalogItemRepository.save(catalogItem);
227
    }
228

    
229
    /**
230
     * Converts catalog DTO to catalog entity
231
     *
232
     * @param catalogItemDto catalog DTO
233
     * @param catalogItem    catalog entity
234
     */
235
    private void convertDtoToEntity(CatalogItemDto catalogItemDto, CatalogItem catalogItem) {
236
        catalogItem.setName(catalogItemDto.getName());
237
        catalogItem.setCertainty(catalogItemDto.getCertainty());
238
        catalogItem.setLatitude(catalogItemDto.getLatitude());
239
        catalogItem.setLongitude(catalogItemDto.getLongitude());
240

    
241
        catalogItem.getBibliography().clear();
242
        catalogItem.getBibliography().addAll(catalogItemDto.getBibliography()
243
                .stream().map(s -> new Bibliography(s, catalogItem)).collect(Collectors.toSet()));
244

    
245
        catalogItem.getTypes().clear();
246
        catalogItem.getTypes().addAll(catalogItemDto.getTypes()
247
                .stream().map(Type::new).collect(Collectors.toSet()));
248

    
249
        catalogItem.getCountries().clear();
250
        catalogItem.getCountries().addAll(catalogItemDto.getCountries()
251
                .stream().map(s -> new Country(s, catalogItem)).collect(Collectors.toSet()));
252

    
253
        catalogItem.getAlternativeNames().clear();
254
        catalogItem.getAlternativeNames().addAll(catalogItemDto.getAlternativeNames()
255
                .stream().map(s -> new AlternativeName(s, catalogItem)).collect(Collectors.toSet()));
256

    
257
        catalogItem.getWrittenForms().clear();
258
        catalogItem.getWrittenForms().addAll(catalogItemDto.getWrittenForms()
259
                .stream().map(s -> new WrittenForm(s, catalogItem)).collect(Collectors.toSet()));
260

    
261
        catalogItem.setDescription(catalogItemDto.getDescription());
262
    }
263

    
264
    /**
265
     * Converts catalog entity to catalog DTO
266
     *
267
     * @param catalogItem catalog entity
268
     * @return catalog DTO
269
     */
270
    private CatalogItemDto convertEntityToDto(CatalogItem catalogItem) {
271
        CatalogItemDto catalogItemDto = new CatalogItemDto();
272
        catalogItemDto.setId(catalogItem.getId());
273
        catalogItemDto.setName(catalogItem.getName());
274
        catalogItemDto.setLatitude(catalogItem.getLatitude());
275
        catalogItemDto.setLongitude(catalogItem.getLongitude());
276
        catalogItemDto.setCertainty(catalogItem.getCertainty());
277
        catalogItemDto.setBibliography(catalogItem.getBibliography()
278
                .stream().map(Bibliography::getSource).collect(Collectors.toSet()));
279
        catalogItemDto.setTypes(catalogItem.getTypes()
280
                .stream().map(Type::getType).collect(Collectors.toSet()));
281
        catalogItemDto.setCountries(catalogItem.getCountries()
282
                .stream().map(Country::getName).collect(Collectors.toSet()));
283
        catalogItemDto.setAlternativeNames(catalogItem.getAlternativeNames()
284
                .stream().map(AlternativeName::getName).collect(Collectors.toSet()));
285
        catalogItemDto.setWrittenForms(catalogItem.getWrittenForms()
286
                .stream().map(WrittenForm::getForm).collect(Collectors.toSet()));
287
        catalogItemDto.setDescription(catalogItem.getDescription());
288
        return catalogItemDto;
289
    }
290

    
291
}
(5-5/6)