• 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/repository/NgsiLdBaseRepository.java
1
package org.fiware.tmforum.common.repository;
2

3
import io.github.wistefan.mapping.EntityVOMapper;
4
import io.github.wistefan.mapping.JavaObjectMapper;
5
import io.micronaut.cache.annotation.CacheInvalidate;
6
import io.micronaut.cache.annotation.CachePut;
7
import io.micronaut.cache.annotation.Cacheable;
8
import io.micronaut.http.HttpStatus;
9
import io.micronaut.http.client.exceptions.HttpClientResponseException;
10
import lombok.RequiredArgsConstructor;
11
import org.fiware.ngsi.api.EntitiesApiClient;
12
import org.fiware.ngsi.model.EntityFragmentVO;
13
import org.fiware.ngsi.model.EntityVO;
14
import org.fiware.tmforum.common.caching.EntityIdKeyGenerator;
15
import org.fiware.tmforum.common.configuration.GeneralProperties;
16
import org.fiware.tmforum.common.exception.DeletionException;
17
import org.fiware.tmforum.common.exception.DeletionExceptionReason;
18
import org.fiware.tmforum.common.exception.NgsiLdRepositoryException;
19
import org.fiware.tmforum.common.mapping.NGSIMapper;
20
import reactor.core.publisher.Mono;
21

22
import java.net.URI;
23
import java.util.Arrays;
24
import java.util.List;
25
import java.util.Optional;
26
import java.util.stream.Stream;
27

28
/**
29
 * Base-Repository implementation for using the NGSI-LD API as a storage backend. Supports caching and asynchronous retrieval of entities.
30
 */
31
@RequiredArgsConstructor
×
32
public abstract class NgsiLdBaseRepository {
33

34
    /**
35
     * Name for the entities cache
36
     */
37
    private static final String ENTITIES_CACHE_NAME = "entities";
38

39
    protected final GeneralProperties generalProperties;
40
    protected final EntitiesApiClient entitiesApi;
41
    protected final JavaObjectMapper javaObjectMapper;
42
    protected final NGSIMapper ngsiMapper;
43
    protected final EntityVOMapper entityVOMapper;
44

45

46
    protected String getLinkHeader() {
47
        return String.format("<%s>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json", generalProperties.getContextUrl());
×
48
    }
49

50
    /**
51
     * Create an entity at the broker and cache it.
52
     *
53
     * @param entityVO     - the entity to be created
54
     * @param ngsiLDTenant - tenant the entity belongs to
55
     * @return completable with the result
56
     */
57
    @CachePut(value = ENTITIES_CACHE_NAME, keyGenerator = EntityIdKeyGenerator.class)
58
    public Mono<Void> createEntity(EntityVO entityVO, String ngsiLDTenant) {
59
        return entitiesApi.createEntity(entityVO, ngsiLDTenant);
×
60
    }
61

62
    /**
63
     * Retrieve entity from the broker or from the cache if they are available there.
64
     *
65
     * @param entityId id of the entity
66
     * @return the entity
67
     */
68
    @Cacheable(ENTITIES_CACHE_NAME)
69
    public Mono<EntityVO> retrieveEntityById(URI entityId) {
70
        return asyncRetrieveEntityById(entityId, generalProperties.getTenant(), null, null, null, getLinkHeader());
×
71
    }
72

73
    /**
74
     * Patch an entity, using the "overwrite" option.
75
     *
76
     * @param entityId         id of the entity
77
     * @param entityFragmentVO the entity elements to be updated
78
     * @return an empty mono
79
     */
80
    @CacheInvalidate(value = ENTITIES_CACHE_NAME, keyGenerator = EntityIdKeyGenerator.class)
81
    public Mono<Void> patchEntity(URI entityId, EntityFragmentVO entityFragmentVO) {
82
        return entitiesApi.updateEntity(entityId, entityFragmentVO, generalProperties.getTenant(), null);
×
83
    }
84

85
    /**
86
     * Create a domain entity
87
     *
88
     * @param domainEntity the entity to be created
89
     * @param <T>          the type of the object
90
     * @return an empty mono
91
     */
92
    public <T> Mono<Void> createDomainEntity(T domainEntity) {
93
        return createEntity(javaObjectMapper.toEntityVO(domainEntity), generalProperties.getTenant());
×
94
    }
95

96
    /**
97
     * Update a domain entity
98
     *
99
     * @param id           id of the entity to be updated
100
     * @param domainEntity the entity to be created
101
     * @param <T>          the type of the object
102
     * @return an empty mono
103
     */
104
    public <T> Mono<Void> updateDomainEntity(String id, T domainEntity) {
105
        return patchEntity(URI.create(id), ngsiMapper.map(javaObjectMapper.toEntityVO(domainEntity)));
×
106
    }
107

108
    /**
109
     * Delete a domain entity
110
     *
111
     * @param id id of the entity to be deleted
112
     * @return an empty mono
113
     */
114
    @CacheInvalidate(value = ENTITIES_CACHE_NAME, keyGenerator = EntityIdKeyGenerator.class)
115
    public Mono<Void> deleteDomainEntity(URI id) {
116
        return entitiesApi
×
117
            .removeEntityById(id, generalProperties.getTenant(), null)
×
118
            .onErrorResume(t -> {
×
119
                if (t instanceof HttpClientResponseException e && e.getStatus().equals(HttpStatus.NOT_FOUND)) {
×
120
                    throw new DeletionException(String.format("Was not able to delete %s, since it does not exist.", id),
×
121
                            DeletionExceptionReason.NOT_FOUND);
122
                }
123
                throw new DeletionException(String.format("Was not able to delete %s.", id),
×
124
                        t,
125
                        DeletionExceptionReason.UNKNOWN);
126
            });
127
    }
128

129
    /**
130
     * Helper method for combining a stream of entites to a single mono.
131
     *
132
     * @param entityVOStream stream of entites
133
     * @param targetClass    target class to map them
134
     * @param <T>            type of the target
135
     * @return a mono, emitting a list of mapped entities
136
     */
137
    protected <T> Mono<List<T>> zipToList(Stream<EntityVO> entityVOStream, Class<T> targetClass) {
138
        return Mono.zip(
×
139
                entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(),
×
140
                oList -> Arrays.stream(oList).map(targetClass::cast).toList()
×
141
        );
142
    }
143

144
    /**
145
     * Uncached call to the broker
146
     */
147
    private Mono<EntityVO> asyncRetrieveEntityById(URI entityId, String ngSILDTenant, String attrs, String type, String options, String link) {
148
        return entitiesApi
×
149
                .retrieveEntityById(entityId, ngSILDTenant, attrs, type, options, link)
×
150
                .onErrorResume(this::handleClientException);
×
151
    }
152

153
    private Mono<EntityVO> handleClientException(Throwable e) {
154
        if (e instanceof HttpClientResponseException httpException && httpException.getStatus().equals(HttpStatus.NOT_FOUND)) {
×
155
            return Mono.empty();
×
156
        }
157
        throw new NgsiLdRepositoryException("Was not able to successfully call the broker.", Optional.of(e));
×
158
    }
159

160
}
161

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