• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wistefan / tmforum-api / #61

18 Oct 2023 12:35PM UTC coverage: 67.631% (+0.1%) from 67.488%
#61

push

web-flow
Configurable NGSI-LD Query format (#32)

* Build different NGSI queries depending if the attr is relationship or property

* Add tests to validate query parser with relationships

* Add missing testing class

* Fix bug removing well known attributes in query parser using fixed-size list

* Use scorpio OR queries

* Fix the type of product spec bundle references

* Update the type of product specs relationships

* Fix errors mapping categories and product specs as references

* Fix config issues with ProductOfferingTerm

* Allow to configure NGSI-LD query options

* Add default NGSI-LD query configuration

* fix config

* fix test call

* fix it

---------

Co-authored-by: Stefan Wiedemann <wistefan@googlemail.com>

65 of 65 new or added lines in 47 files covered. (100.0%)

2804 of 4146 relevant lines covered (67.63%)

0.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/common/src/main/java/org/fiware/tmforum/common/rest/AbstractApiController.java
1
package org.fiware.tmforum.common.rest;
2

3
import io.micronaut.http.HttpRequest;
4
import io.micronaut.http.HttpResponse;
5
import io.micronaut.http.client.exceptions.HttpClientResponseException;
6
import io.micronaut.http.context.ServerRequestContext;
7
import lombok.RequiredArgsConstructor;
8
import lombok.extern.slf4j.Slf4j;
9
import org.fiware.tmforum.common.notification.EventHandler;
10
import org.fiware.tmforum.common.domain.EntityWithId;
11
import org.fiware.tmforum.common.exception.TmForumException;
12
import org.fiware.tmforum.common.exception.TmForumExceptionReason;
13
import org.fiware.tmforum.common.mapping.IdHelper;
14
import org.fiware.tmforum.common.querying.QueryParser;
15
import org.fiware.tmforum.common.repository.TmForumRepository;
16
import org.fiware.tmforum.common.validation.ReferenceValidationService;
17
import org.fiware.tmforum.common.validation.ReferencedEntity;
18
import reactor.core.publisher.Mono;
19

20
import java.net.URI;
21
import java.util.Arrays;
22
import java.util.List;
23
import java.util.Map;
24
import java.util.Optional;
25
import java.util.concurrent.atomic.AtomicReference;
26
import java.util.function.Consumer;
27
import java.util.stream.Stream;
28

29
import static org.fiware.tmforum.common.CommonConstants.DEFAULT_LIMIT;
30
import static org.fiware.tmforum.common.CommonConstants.DEFAULT_OFFSET;
31

32
@Slf4j
×
33
@RequiredArgsConstructor
×
34
public abstract class AbstractApiController<T> {
35

36
        protected final QueryParser queryParser;
37
        protected final ReferenceValidationService validationService;
38
        protected final TmForumRepository repository;
39
        private final EventHandler eventHandler;
40

41
        protected Mono<T> getCheckingMono(T entityToCheck, List<List<? extends ReferencedEntity>> referencedEntities) {
42
                Mono<T> checkingMono = Mono.just(entityToCheck);
×
43
                for (List<? extends ReferencedEntity> referencedEntitiesList : referencedEntities) {
×
44
                        if (referencedEntitiesList != null && !referencedEntitiesList.isEmpty()) {
×
45
                                checkingMono = Mono.zip(checkingMono,
×
46
                                                validationService.getCheckingMono(referencedEntitiesList, entityToCheck), (p1, p2) -> p1);
×
47
                        }
48
                }
×
49
                return checkingMono;
×
50
        }
51

52
        protected Mono<T> create(Mono<T> checkingMono, Class<T> entityClass) {
53
                return checkingMono
×
54
                                .flatMap(checkedResult -> repository.createDomainEntity(checkedResult)
×
55
                                                .then(eventHandler.handleCreateEvent(checkedResult))
×
56
                                                .then(Mono.just(checkedResult)))
×
57
                                .onErrorMap(t -> {
×
58
                                        if (t instanceof HttpClientResponseException e) {
×
59
                                                return switch (e.getStatus()) {
×
60
                                                        case CONFLICT -> new TmForumException(
×
61
                                                                        String.format("Conflict on creating the entity: %s", e.getMessage()),
×
62
                                                                        TmForumExceptionReason.CONFLICT);
63
                                                        case BAD_REQUEST -> new TmForumException(
×
64
                                                                        String.format("Did not receive a valid entity: %s.", e.getMessage()),
×
65
                                                                        TmForumExceptionReason.INVALID_DATA);
66
                                                        default -> new TmForumException(
×
67
                                                                        String.format("Unspecified downstream error: %s", e.getMessage()),
×
68
                                                                        TmForumExceptionReason.UNKNOWN);
69
                                                };
70
                                        } else {
71
                                                return t;
×
72
                                        }
73
                                })
74
                                .cast(entityClass);
×
75
        }
76

77
        protected Mono<HttpResponse<Object>> delete(String id) {
78
                // non-ngsi-ld ids cannot exist.
79
                if (!IdHelper.isNgsiLdId(id)) {
×
80
                        throw new TmForumException("Did not receive a valid id, such entity cannot exist.",
×
81
                                        TmForumExceptionReason.NOT_FOUND);
82
                }
83

84
                URI idUri = URI.create(id);
×
85
                return repository.retrieveEntityById(idUri)
×
86
                                .switchIfEmpty(Mono.error(new TmForumException("No such entity exists.",
×
87
                                                TmForumExceptionReason.NOT_FOUND)))
88
                                .flatMap(entityVO ->
×
89
                                        repository.deleteDomainEntity(idUri)
×
90
                                                .then(eventHandler.handleDeleteEvent(entityVO))
×
91
                                                .then(Mono.just(HttpResponse.noContent())));
×
92
        }
93

94
        protected <R> Mono<Stream<R>> list(Integer offset, Integer limit, String type, Class<R> entityClass) {
95

96
                Optional<HttpRequest<Object>> optionalHttpRequest = ServerRequestContext.currentRequest();
×
97
                String query = null;
×
98
                if (optionalHttpRequest.isEmpty()) {
×
99
                        log.warn("The original request is not available, no filters will be applied.");
×
100
                } else {
101
                        HttpRequest<Object> theRequest = optionalHttpRequest.get();
×
102
                        Map<String, List<String>> parameters = theRequest.getParameters().asMap();
×
103
                        if (QueryParser.hasFilter(parameters)) {
×
104
                                log.debug("A filter is included in the request.");
×
105
                                String queryString = theRequest.getUri().getQuery();
×
106
                                query = queryParser.toNgsiLdQuery(entityClass, queryString);
×
107
                        }
108
                }
109
                offset = Optional.ofNullable(offset).orElse(DEFAULT_OFFSET);
×
110
                limit = Optional.ofNullable(limit).orElse(DEFAULT_LIMIT);
×
111

112
                if (offset < 0 || limit < 1) {
×
113
                        throw new TmForumException(String.format("Invalid offset %s or limit %s.", offset, limit),
×
114
                                        TmForumExceptionReason.INVALID_DATA);
115
                }
116

117
                return repository
×
118
                                .findEntities(offset, limit, type, entityClass, query)
×
119
                                .map(List::stream);
×
120
        }
121

122
        protected <R> Mono<R> retrieve(String id, Class<R> entityClass) {
123
                // non-ngsi-ld ids cannot exist.
124
                if (!IdHelper.isNgsiLdId(id)) {
×
125
                        throw new TmForumException("Did not receive a valid id, such entity cannot exist.",
×
126
                                        TmForumExceptionReason.NOT_FOUND);
127
                }
128
                return repository
×
129
                                .get(URI.create(id), entityClass);
×
130
        }
131

132
        protected Mono<T> patch(String id, T updatedObject, Mono<T> checkingMono, Class<T> entityClass) {
133
                URI idUri = URI.create(id);
×
134

135
                AtomicReference<T> old = new AtomicReference<>();
×
136
                return repository
×
137
                                .get(idUri, entityClass)
×
138
                                .switchIfEmpty(
×
139
                                                Mono.error(new TmForumException("No such entity exists.", TmForumExceptionReason.NOT_FOUND)))
×
140
                                .flatMap(entity -> {
×
141
                                        old.set(entity);
×
142
                                        return checkingMono;
×
143
                                })
144
                                .flatMap(entity -> repository.updateDomainEntity(id, updatedObject)
×
145
                                                                .then(repository.get(idUri, entityClass))
×
146
                                                                .flatMap(updatedState -> eventHandler.handleUpdateEvent(updatedState, old.get())
×
147
                                                                                .then(Mono.just(updatedState))
×
148
                                                                )
149
                                );
150
        }
151

152
        protected <R extends EntityWithId> Mono<T> relatedEntityHandlingMono(T entity, Mono<T> entityMono,
153
                        List<R> relatedList, Consumer<List<R>> entityUpdater, Class<R> relatedEntityClass) {
154
                List<R> relatedEntities = Optional.ofNullable(relatedList).orElseGet(List::of);
×
155
                if (!relatedEntities.isEmpty()) {
×
156
                        Mono<List<R>> relatedEntitiesMono = Mono.zip(
×
157
                                        relatedEntities
158
                                                        .stream()
×
159
                                                        .map(re ->
×
160
                                                                        repository
×
161
                                                                                        .updateDomainEntity(re.getId().toString(), re)
×
162
                                                                                        .onErrorResume(t -> repository.createDomainEntity(re))
×
163
                                                                                        .then(Mono.just(re))
×
164
                                                        )
165
                                                        .toList(),
×
166
                                        t -> Arrays.stream(t).map(relatedEntityClass::cast).toList());
×
167

168
                        Mono<T> updatingMono = relatedEntitiesMono
×
169
                                        .map(updatedRelatedEntity -> {
×
170
                                                entityUpdater.accept(updatedRelatedEntity);
×
171
                                                return entity;
×
172
                                        });
173
                        entityMono = Mono.zip(entityMono, updatingMono, (e1, e2) -> e1);
×
174
                }
175
                return entityMono;
×
176
        }
177

178
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc