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

FIWARE / contract-management / #68

29 Oct 2025 11:26AM UTC coverage: 1.686% (+0.04%) from 1.651%
#68

Pull #12

wistefan
fixes from pr review
Pull Request #12: Support for central marketplace and policy creation

117 of 1238 new or added lines in 31 files covered. (9.45%)

5 existing lines in 2 files now uncovered.

587 of 34807 relevant lines covered (1.69%)

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/dsp/RainbowQuoteHandler.java
1
package org.fiware.iam.dsp;
2

3
import com.fasterxml.jackson.databind.ObjectMapper;
4
import io.micronaut.context.annotation.Requires;
5
import io.micronaut.http.HttpResponse;
6
import jakarta.inject.Singleton;
7
import lombok.RequiredArgsConstructor;
8
import lombok.extern.slf4j.Slf4j;
9
import org.fiware.iam.configuration.GeneralProperties;
10
import org.fiware.iam.handlers.QuoteHandler;
11
import org.fiware.iam.exception.RainbowException;
12
import org.fiware.iam.tmforum.TMForumAdapter;
13
import org.fiware.iam.tmforum.quote.model.ProductOfferingRefVO;
14
import org.fiware.iam.tmforum.quote.model.QuoteItemVO;
15
import org.fiware.iam.tmforum.quote.model.QuoteStateTypeVO;
16
import org.fiware.iam.tmforum.quote.model.QuoteVO;
17
import org.fiware.rainbow.model.NegotiationRequestVO;
18
import org.fiware.rainbow.model.ObligationVO;
19
import org.fiware.rainbow.model.OfferVO;
20
import org.fiware.rainbow.model.PermissionVO;
21
import reactor.core.publisher.Mono;
22

23
import java.util.*;
24
import java.util.stream.Stream;
25

26
import static org.fiware.iam.dsp.PriceMapper.PAYMENT_ACTION;
27
import static org.fiware.iam.tmforum.TMForumAdapter.CONSUMER_ROLE;
28

29
@Requires(condition = GeneralProperties.RainbowCondition.class)
30
@RequiredArgsConstructor
31
@Singleton
NEW
32
@Slf4j
×
33
public class RainbowQuoteHandler implements QuoteHandler {
34

35

36
    private static final String URN_UUID_TEMPLATE = "urn:uuid:%s";
37
    private static final String OFFERED_STATE = "dspace:OFFERED";
38
    private static final String AGREED_STATE = "dspace:AGREED";
39
    private static final String TERMINATED_STATE = "dspace:TERMINATED";
40
    private static final String QUOTE_REJECTED_STATE = "rejected";
41
    private static final String POLICY_KEY = "policy";
42

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

49
    @Override
50
    public Mono<HttpResponse<?>> handleQuoteCreation(QuoteVO quoteVO) {
NEW
51
        List<PermissionVO> permissionVOS = new ArrayList<>(getPermissionsFromQuote(objectMapper, quoteVO));
×
52

NEW
53
        return tmForumAdapter.getConsumerDid(quoteVO)
×
NEW
54
                .flatMap(id -> rainbowAdapter.createParticipant(id, CONSUMER_ROLE))
×
NEW
55
                .onErrorMap(t -> new RainbowException("Was not able to create consumer.", t))
×
NEW
56
                .flatMap(r -> getObligationFromQuote(quoteVO))
×
NEW
57
                .flatMap(obligation -> {
×
NEW
58
                    String offerId = getOfferIdFromQuote(quoteVO);
×
NEW
59
                    return tmForumAdapter.getOfferingParameters(offerId)
×
NEW
60
                            .map(offeringParams -> {
×
NEW
61
                                permissionVOS.add(new PermissionVO()
×
NEW
62
                                        .odrlColonAction(offeringParams.action()));
×
NEW
63
                                OfferVO offerVO = new OfferVO()
×
NEW
64
                                        .atId(offerId)
×
NEW
65
                                        .odrlColonTarget(offeringParams.target())
×
NEW
66
                                        .odrlColonPermission(permissionVOS);
×
NEW
67
                                if (obligation.getOdrlColonConstraint() != null && !obligation.getOdrlColonConstraint().isEmpty()) {
×
NEW
68
                                    offerVO.odrlColonObligation(List.of(obligation));
×
69
                                }
NEW
70
                                return new NegotiationRequestVO()
×
NEW
71
                                        .dspaceColonCallbackAddress("")
×
NEW
72
                                        .dspaceColonConsumerPid(String.format(URN_UUID_TEMPLATE, UUID.randomUUID()))
×
NEW
73
                                        .dspaceColonOffer(offerVO);
×
74
                            });
75
                })
NEW
76
                .onErrorMap(t -> {
×
NEW
77
                    throw new RainbowException("Was not able to get the offering parameters.", t);
×
78
                })
NEW
79
                .flatMap(negotiationRequestVO ->
×
NEW
80
                        rainbowAdapter
×
NEW
81
                                .createNegotiationRequest(negotiationRequestVO)
×
NEW
82
                                .flatMap(id -> tmForumAdapter.updateExternalId(quoteVO, id))
×
NEW
83
                                .map(t -> HttpResponse.noContent()));
×
84
    }
85

86
    @Override
87
    public Mono<HttpResponse<?>> handleQuoteStateChange(QuoteVO quoteVO) {
NEW
88
        QuoteStateTypeVO quoteStateTypeVO = quoteVO.getState();
×
NEW
89
        log.debug("Quote state is {}", quoteStateTypeVO);
×
NEW
90
        return switch (quoteStateTypeVO) {
×
91
            case APPROVED ->
NEW
92
                    rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), OFFERED_STATE)
×
NEW
93
                            .map(t -> HttpResponse.noContent());
×
NEW
94
            case ACCEPTED -> tmForumAdapter.getConsumerDid(quoteVO)
×
NEW
95
                    .flatMap(consumerDid ->
×
NEW
96
                            rainbowAdapter
×
NEW
97
                                    .createAgreementAfterNegotiation(quoteVO.getExternalId(), consumerDid, generalProperties.getDid())
×
NEW
98
                                    .flatMap(r -> rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), AGREED_STATE)
×
NEW
99
                                            .map(t -> HttpResponse.noContent())));
×
100
            // a lot of requests can just be ignored
NEW
101
            default -> Mono.just(HttpResponse.noContent());
×
102
        };
103
    }
104

105
    @Override
106
    public Mono<HttpResponse<?>> handleQuoteDeletion(QuoteVO quoteVO) {
NEW
107
        if (quoteVO.getExternalId() == null && !quoteVO.getExternalId().isEmpty()) {
×
NEW
108
            return rainbowAdapter.updateNegotiationProcessByProviderId(quoteVO.getExternalId(), TERMINATED_STATE)
×
NEW
109
                    .map(t -> HttpResponse.noContent());
×
110
        }
111

NEW
112
        return Mono.just(HttpResponse.noContent());
×
113
    }
114

115
    private String getOfferIdFromQuote(QuoteVO quoteVO) {
NEW
116
        return getRelevantQuoteItems(quoteVO)
×
NEW
117
                .map(QuoteItemVO::getProductOffering)
×
NEW
118
                .map(ProductOfferingRefVO::getId)
×
NEW
119
                .findFirst()
×
NEW
120
                .orElseThrow(() -> new IllegalArgumentException("The event does not reference an offer."));
×
121
    }
122

123
    private Stream<QuoteItemVO> getRelevantQuoteItems(QuoteVO quoteVO) {
NEW
124
        return quoteVO
×
NEW
125
                .getQuoteItem()
×
NEW
126
                .stream()
×
NEW
127
                .filter(qi -> !qi.getState().equals(QUOTE_REJECTED_STATE));
×
128
    }
129

130
    private List<Policy> getPoliciesFromQuote(QuoteVO quoteVO) {
NEW
131
        return getRelevantQuoteItems(quoteVO)
×
NEW
132
                .map(QuoteItemVO::getUnknownProperties)
×
NEW
133
                .map(Map::entrySet)
×
NEW
134
                .flatMap(Set::stream)
×
NEW
135
                .filter(ap -> ap.getKey().equals(POLICY_KEY))
×
NEW
136
                .map(Map.Entry::getValue)
×
NEW
137
                .filter(List.class::isInstance)
×
NEW
138
                .map(List.class::cast)
×
NEW
139
                .flatMap(List::stream)
×
NEW
140
                .map(v -> objectMapper.convertValue(v, Policy.class))
×
NEW
141
                .toList();
×
142
    }
143

144
    private List<PermissionVO> getPermissionsFromQuote(ObjectMapper objectMapper, QuoteVO quoteVO) {
NEW
145
        return getPoliciesFromQuote(quoteVO)
×
NEW
146
                .stream()
×
NEW
147
                .map(o -> objectMapper.convertValue(o, Policy.class))
×
NEW
148
                .map(Policy::getPermission)
×
NEW
149
                .flatMap(List::stream)
×
NEW
150
                .toList();
×
151
    }
152

153

154
    private Mono<ObligationVO> getObligationFromQuote(QuoteVO quoteVO) {
NEW
155
        ObligationVO obligationVO = new ObligationVO();
×
NEW
156
        obligationVO.odrlColonAction(PAYMENT_ACTION);
×
157

NEW
158
        return Mono.zip(
×
NEW
159
                getRelevantQuoteItems(quoteVO)
×
NEW
160
                        .map(QuoteItemVO::getQuoteItemPrice)
×
NEW
161
                        .flatMap(List::stream)
×
NEW
162
                        .map(priceMapper::toObligationConstraints)
×
NEW
163
                        .toList(),
×
NEW
164
                cons -> obligationVO.odrlColonConstraint(
×
NEW
165
                        Arrays.asList(cons)
×
NEW
166
                                .stream()
×
NEW
167
                                .filter(List.class::isInstance)
×
NEW
168
                                .map(List.class::cast)
×
NEW
169
                                .flatMap(List::stream)
×
NEW
170
                                .toList()));
×
171
    }
172
}
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