1
2
3
4
5
6 package org.tailormap.api.controller.admin;
7
8 import java.io.Serializable;
9 import org.apache.commons.lang3.StringUtils;
10 import org.geotools.api.filter.FilterFactory;
11 import org.geotools.factory.CommonFactoryFinder;
12 import org.geotools.util.factory.GeoTools;
13 import org.springframework.beans.factory.annotation.Value;
14 import org.springframework.http.HttpStatus;
15 import org.springframework.http.MediaType;
16 import org.springframework.http.ResponseEntity;
17 import org.springframework.web.bind.annotation.ExceptionHandler;
18 import org.springframework.web.bind.annotation.GetMapping;
19 import org.springframework.web.bind.annotation.PathVariable;
20 import org.springframework.web.bind.annotation.RequestParam;
21 import org.springframework.web.bind.annotation.RestController;
22 import org.springframework.web.server.ResponseStatusException;
23 import org.tailormap.api.geotools.featuresources.FeatureSourceFactoryHelper;
24 import org.tailormap.api.persistence.TMFeatureType;
25 import org.tailormap.api.persistence.helper.UniqueValuesHelper;
26 import org.tailormap.api.persistence.json.TMAttributeDescriptor;
27 import org.tailormap.api.repository.FeatureTypeRepository;
28 import org.tailormap.api.viewer.model.ErrorResponse;
29 import org.tailormap.api.viewer.model.UniqueValuesResponse;
30
31 @RestController
32 public class UniqueValuesAdminController {
33 private final FeatureTypeRepository featureTypeRepository;
34
35 private final FeatureSourceFactoryHelper featureSourceFactoryHelper;
36
37 @Value("${tailormap-api.unique.use_geotools_unique_function:true}")
38 private boolean useGeotoolsUniqueFunction;
39
40 private final FilterFactory ff = CommonFactoryFinder.getFilterFactory(GeoTools.getDefaultHints());
41
42 public UniqueValuesAdminController(
43 FeatureTypeRepository featureTypeRepository, FeatureSourceFactoryHelper featureSourceFactoryHelper) {
44 this.featureTypeRepository = featureTypeRepository;
45 this.featureSourceFactoryHelper = featureSourceFactoryHelper;
46 }
47
48 @ExceptionHandler({ResponseStatusException.class})
49 public ResponseEntity<?> handleException(ResponseStatusException ex) {
50
51 return ResponseEntity.status(ex.getStatusCode())
52 .contentType(MediaType.APPLICATION_JSON)
53 .body(new ErrorResponse()
54 .message(
55 ex.getReason() != null
56 ? ex.getReason()
57 : ex.getBody().getTitle())
58 .code(ex.getStatusCode().value()));
59 }
60
61 @GetMapping(
62 path = "${tailormap-api.admin.base-path}/unique-values/{featureTypeId}/{attributeName}",
63 produces = MediaType.APPLICATION_JSON_VALUE)
64 public ResponseEntity<Serializable> getUniqueValues(
65 @PathVariable Long featureTypeId,
66 @PathVariable String attributeName,
67 @RequestParam(required = false) String filter)
68 throws ResponseStatusException {
69 if (StringUtils.isBlank(attributeName)) {
70 throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Attribute name is required");
71 }
72
73 TMFeatureType tmft = this.featureTypeRepository
74 .findById(featureTypeId)
75 .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Feature type not found"));
76
77 if (tmft.getAttributeByName(attributeName).isEmpty()) {
78 throw new ResponseStatusException(
79 HttpStatus.BAD_REQUEST,
80 "Attribute does not exist, available attributes: "
81 + tmft.getAttributes().stream()
82 .map(TMAttributeDescriptor::getName)
83 .toList());
84 }
85
86 UniqueValuesResponse response = UniqueValuesHelper.getUniqueValues(
87 tmft, attributeName, filter, ff, featureSourceFactoryHelper, useGeotoolsUniqueFunction);
88 return ResponseEntity.status(HttpStatus.OK).body(response);
89 }
90 }