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

wistefan / tmforum-api / #49

29 Sep 2023 06:20AM UTC coverage: 67.488% (-4.3%) from 71.815%
#49

push

web-flow
Notifications (#23)

* Squashed commits

* Added cache invalidation for entity deletion

* Updated error message

618 of 618 new or added lines in 86 files covered. (100.0%)

2794 of 4140 relevant lines covered (67.49%)

0.67 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 ReferenceValidationService validationService;
37
        protected final TmForumRepository repository;
38
        private final EventHandler eventHandler;
39

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

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

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

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

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

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

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

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

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

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

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

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

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

177
}
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