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

FIWARE / contract-management / #35

08 Apr 2025 12:16PM UTC coverage: 1.745% (+0.8%) from 0.982%
#35

Pull #5

wistefan
implement idsa
Pull Request #5: integrate contract negotiation

25 of 340 new or added lines in 12 files covered. (7.35%)

16673 existing lines in 365 files now uncovered.

588 of 33695 relevant lines covered (1.75%)

0.02 hits per line

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

0.0
/src/main/java/org/fiware/iam/tmforum/handlers/QuoteEventHandler.java
1
package org.fiware.iam.tmforum.handlers;
2

3
import com.fasterxml.jackson.databind.ObjectMapper;
4
import io.micronaut.http.HttpResponse;
5
import jakarta.inject.Singleton;
6
import lombok.RequiredArgsConstructor;
7
import lombok.extern.slf4j.Slf4j;
8
import org.fiware.iam.PriceMapper;
9
import org.fiware.iam.configuration.GeneralProperties;
10
import org.fiware.iam.domain.Policy;
11
import org.fiware.iam.dsp.RainbowAdapter;
12
import org.fiware.iam.exception.RainbowException;
13
import org.fiware.iam.tmforum.TMForumAdapter;
14
import org.fiware.iam.tmforum.quote.model.*;
15
import org.fiware.rainbow.model.NegotiationRequestVO;
16
import org.fiware.rainbow.model.ObligationVO;
17
import org.fiware.rainbow.model.OfferVO;
18
import org.fiware.rainbow.model.PermissionVO;
19
import reactor.core.publisher.Mono;
20

21
import java.util.*;
22
import java.util.stream.Stream;
23

24
import static org.fiware.iam.PriceMapper.PAYMENT_ACTION;
25
import static org.fiware.iam.tmforum.TMForumAdapter.CONSUMER_ROLE;
26

27
/**
28
 * Handle all incoming events in connection to Quote
29
 */
30
@RequiredArgsConstructor
31
@Singleton
NEW
32
@Slf4j
×
33
public class QuoteEventHandler implements EventHandler {
34

35
        private static final String URN_UUID_TEMPLATE = "urn:uuid:%s";
36

37

38
        private static final String CREATE_EVENT = "QuoteCreateEvent";
39
        private static final String DELETE_EVENT = "QuoteDeleteEvent";
40
        private static final String STATE_CHANGE_EVENT = "QuoteStateChangeEvent";
41
        private static final String ATTRIBUTE_CHANGE_EVENT = "QuoteAttributeValueChangeEvent";
42

NEW
43
        private static final List<String> SUPPORTED_EVENT_TYPES = List.of(CREATE_EVENT, DELETE_EVENT, STATE_CHANGE_EVENT, ATTRIBUTE_CHANGE_EVENT);
×
44

45
        private final ObjectMapper objectMapper;
46
        private final GeneralProperties generalProperties;
47
        private final PriceMapper priceMapper;
48
        private final TMForumAdapter tmForumAdapter;
49
        private final RainbowAdapter rainbowAdapter;
50

51

52
        @Override
53
        public boolean isEventTypeSupported(String eventType) {
NEW
54
                return SUPPORTED_EVENT_TYPES.contains(eventType);
×
55
        }
56

57
        @Override
58
        public Mono<HttpResponse<?>> handleEvent(String eventType, Map<String, Object> event) {
NEW
59
                return switch (eventType) {
×
NEW
60
                        case CREATE_EVENT -> handleQuoteCreation(event);
×
NEW
61
                        case STATE_CHANGE_EVENT, ATTRIBUTE_CHANGE_EVENT -> handleQuoteStateChange(event);
×
NEW
62
                        case DELETE_EVENT -> handleQuoteDeletion(event);
×
NEW
63
                        default -> throw new IllegalArgumentException("Even type %s is not supported.".formatted(eventType));
×
64
                };
65
        }
66

67
        private Mono<HttpResponse<?>> handleQuoteCreation(Map<String, Object> event) {
NEW
68
                QuoteCreateEventVO quoteCreateEventVO = objectMapper.convertValue(event, QuoteCreateEventVO.class);
×
NEW
69
                QuoteVO quoteVO = quoteCreateEventVO.getEvent()
×
NEW
70
                                .getQuote();
×
NEW
71
                List<PermissionVO> permissionVOS = new ArrayList<>(getPermissionsFromQuote(quoteVO));
×
72

NEW
73
                return tmForumAdapter.getConsumerDid(quoteVO)
×
NEW
74
                                .flatMap(id -> rainbowAdapter.createParticipant(id, CONSUMER_ROLE))
×
NEW
75
                                .onErrorMap(t -> new RainbowException("Was not able to create consumer.", t))
×
NEW
76
                                .flatMap(r -> getObligationFromQuote(quoteVO))
×
NEW
77
                                .flatMap(obligation -> {
×
NEW
78
                                        String offerId = getOfferIdFromQuote(quoteVO);
×
NEW
79
                                        return tmForumAdapter.getOfferingParameters(offerId)
×
NEW
80
                                                        .map(offeringParams -> {
×
NEW
81
                                                                permissionVOS.add(new PermissionVO()
×
NEW
82
                                                                                .odrlColonAction(offeringParams.action()));
×
NEW
83
                                                                OfferVO offerVO = new OfferVO()
×
NEW
84
                                                                                .atId(offerId)
×
NEW
85
                                                                                .odrlColonTarget(offeringParams.target())
×
NEW
86
                                                                                .odrlColonPermission(permissionVOS);
×
NEW
87
                                                                if (obligation.getOdrlColonConstraint() != null && !obligation.getOdrlColonConstraint().isEmpty()) {
×
NEW
88
                                                                        offerVO.odrlColonObligation(List.of(obligation));
×
89
                                                                }
NEW
90
                                                                return new NegotiationRequestVO()
×
NEW
91
                                                                                .dspaceColonCallbackAddress("")
×
NEW
92
                                                                                .dspaceColonConsumerPid(String.format(URN_UUID_TEMPLATE, UUID.randomUUID()))
×
NEW
93
                                                                                .dspaceColonOffer(offerVO);
×
94
                                                        });
95
                                })
NEW
96
                                .onErrorMap(t -> {
×
NEW
97
                                        throw new RainbowException("Was not able to get the offering parameters.", t);
×
98
                                })
NEW
99
                                .flatMap(negotiationRequestVO ->
×
NEW
100
                                                rainbowAdapter
×
NEW
101
                                                                .createNegotiationRequest(negotiationRequestVO)
×
NEW
102
                                                                .flatMap(id -> tmForumAdapter.updateExternalId(quoteVO, id))
×
NEW
103
                                                                .map(t -> HttpResponse.noContent()));
×
104
        }
105

106
        private Mono<ObligationVO> getObligationFromQuote(QuoteVO quoteVO) {
NEW
107
                ObligationVO obligationVO = new ObligationVO();
×
NEW
108
                obligationVO.odrlColonAction(PAYMENT_ACTION);
×
109

NEW
110
                return Mono.zip(
×
NEW
111
                                getRelevantQuoteItems(quoteVO)
×
NEW
112
                                                .map(QuoteItemVO::getQuoteItemPrice)
×
NEW
113
                                                .flatMap(List::stream)
×
NEW
114
                                                .map(priceMapper::toObligationConstraints)
×
NEW
115
                                                .toList(),
×
NEW
116
                                cons -> obligationVO.odrlColonConstraint(
×
NEW
117
                                                Arrays.asList(cons)
×
NEW
118
                                                                .stream()
×
NEW
119
                                                                .filter(List.class::isInstance)
×
NEW
120
                                                                .map(List.class::cast)
×
NEW
121
                                                                .flatMap(List::stream)
×
NEW
122
                                                                .toList()));
×
123
        }
124

125
        private Mono<HttpResponse<?>> handleQuoteStateChange(Map<String, Object> event) {
NEW
126
                QuoteStateChangeEventVO quoteStateChangeEventVO = objectMapper.convertValue(event, QuoteStateChangeEventVO.class);
×
NEW
127
                QuoteVO quoteVO = quoteStateChangeEventVO.getEvent()
×
NEW
128
                                .getQuote();
×
129

NEW
130
                List<PermissionVO> permissionVOS = new ArrayList<>(getPermissionsFromQuote(quoteVO));
×
NEW
131
                QuoteStateTypeVO quoteStateTypeVO = quoteVO.getState();
×
NEW
132
                return switch (quoteStateTypeVO) {
×
133
                        case APPROVED ->
NEW
134
                                        rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), "dspace:OFFERED", permissionVOS)
×
NEW
135
                                                        .map(t -> HttpResponse.noContent());
×
NEW
136
                        case ACCEPTED -> tmForumAdapter.getConsumerDid(quoteVO)
×
NEW
137
                                        .flatMap(consumerDid ->
×
NEW
138
                                                        rainbowAdapter
×
NEW
139
                                                                        .createAgreementAfterNegotiation(quoteVO.getExternalId(), consumerDid, generalProperties.getDid())
×
NEW
140
                                                                        .flatMap(r -> rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), "dspace:AGREED", permissionVOS)
×
NEW
141
                                                                                        .map(t -> HttpResponse.noContent())));
×
NEW
142
                        default -> Mono.just(HttpResponse.badRequest());
×
143
                };
144
        }
145

146
        private Mono<HttpResponse<?>> handleQuoteDeletion(Map<String, Object> event) {
NEW
147
                QuoteDeleteEventVO quoteDeleteEventVO = objectMapper.convertValue(event, QuoteDeleteEventVO.class);
×
NEW
148
                QuoteVO quoteVO = quoteDeleteEventVO.getEvent()
×
NEW
149
                                .getQuote();
×
150

NEW
151
                if (quoteVO.getExternalId() == null && !quoteVO.getExternalId().isEmpty()) {
×
NEW
152
                        return rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), "dspace:TERMINATED", List.of())
×
NEW
153
                                        .map(t -> HttpResponse.noContent());
×
154
                }
155

NEW
156
                return Mono.just(HttpResponse.noContent());
×
157
        }
158

159
        private String getOfferIdFromQuote(QuoteVO quoteVO) {
NEW
160
                return getRelevantQuoteItems(quoteVO)
×
NEW
161
                                .map(QuoteItemVO::getProductOffering)
×
NEW
162
                                .map(org.fiware.iam.tmforum.quote.model.ProductOfferingRefVO::getId)
×
NEW
163
                                .findFirst()
×
NEW
164
                                .orElseThrow(() -> new IllegalArgumentException("The event does not reference an offer."));
×
165
        }
166

167
        private Stream<QuoteItemVO> getRelevantQuoteItems(QuoteVO quoteVO) {
NEW
168
                return quoteVO
×
NEW
169
                                .getQuoteItem()
×
NEW
170
                                .stream()
×
NEW
171
                                .filter(qi -> !qi.getState().equals("rejected"));
×
172
        }
173

174
        private List<Policy> getPoliciesFromQuote(QuoteVO quoteVO) {
NEW
175
                return getRelevantQuoteItems(quoteVO)
×
NEW
176
                                .map(QuoteItemVO::getUnknownProperties)
×
NEW
177
                                .map(Map::entrySet)
×
NEW
178
                                .flatMap(Set::stream)
×
NEW
179
                                .filter(ap -> ap.getKey().equals("policy"))
×
NEW
180
                                .map(Map.Entry::getValue)
×
NEW
181
                                .filter(List.class::isInstance)
×
NEW
182
                                .map(List.class::cast)
×
NEW
183
                                .flatMap(List::stream)
×
NEW
184
                                .map(v -> objectMapper.convertValue(v, Policy.class))
×
NEW
185
                                .toList();
×
186
        }
187

188
        private List<PermissionVO> getPermissionsFromQuote(QuoteVO quoteVO) {
NEW
189
                return getPoliciesFromQuote(quoteVO)
×
NEW
190
                                .stream()
×
NEW
191
                                .map(o -> objectMapper.convertValue(o, Policy.class))
×
NEW
192
                                .map(Policy::getPermission)
×
NEW
193
                                .flatMap(List::stream)
×
NEW
194
                                .toList();
×
195
        }
196
}
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

© 2026 Coveralls, Inc