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

FIWARE / contract-management / #69

30 Oct 2025 07:38AM UTC coverage: 1.686% (+0.04%) from 1.651%
#69

Pull #12

wistefan
improve organization creation and cleanup
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

35.63
/src/main/java/org/fiware/iam/tmforum/TMForumAdapter.java
1
package org.fiware.iam.tmforum;
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.dsp.OfferingParameters;
11
import org.fiware.iam.exception.TMForumException;
12
import org.fiware.iam.tmforum.agreement.api.AgreementApiClient;
13
import org.fiware.iam.tmforum.agreement.model.*;
14
import org.fiware.iam.tmforum.productcatalog.api.ProductOfferingApiClient;
15
import org.fiware.iam.tmforum.productcatalog.api.ProductSpecificationApiClient;
16
import org.fiware.iam.tmforum.productcatalog.model.*;
17
import org.fiware.iam.tmforum.productorder.api.ProductOrderApiClient;
18
import org.fiware.iam.tmforum.productorder.model.AgreementRefVO;
19
import org.fiware.iam.tmforum.productorder.model.ProductOrderUpdateVO;
20
import org.fiware.iam.tmforum.productorder.model.ProductOrderVO;
21
import org.fiware.iam.tmforum.quote.api.QuoteApiClient;
22
import org.fiware.iam.tmforum.quote.model.QuoteUpdateVO;
23
import org.fiware.iam.tmforum.quote.model.QuoteVO;
24
import reactor.core.publisher.Mono;
25

26
import java.util.List;
27

28
/**
29
 * Adapter to handle communication with TMForum APIs.
30
 */
31
@Requires(condition = GeneralProperties.TmForumCondition.class)
32
@Singleton
33
@RequiredArgsConstructor
34
@Slf4j
1✔
35
public class TMForumAdapter {
36

37
    public static final String DATA_SPACE_PROTOCOL_AGREEMENT_ID = "Data-Space-Protocol-Agreement-Id";
38
    public static final String CONSUMER_ROLE = "Consumer";
39

40
    private final ObjectMapper objectMapper;
41

42
    private final OrganizationResolver organizationResolver;
43
    private final ProductOrderApiClient productOrderApiClient;
44
    private final ProductOfferingApiClient productOfferingApiClient;
45
    private final ProductSpecificationApiClient productSpecificationApiClient;
46
    private final AgreementApiClient agreementApiClient;
47
    private final QuoteApiClient quoteApiClient;
48

49
    /**
50
     * Create a TMForum Agreement and connect it with product order its coming from.
51
     */
52
    public Mono<String> createAgreement(String productOrderId, String productOfferingId, String agreementId, List<RelatedPartyTmfVO> relatedParties) {
53
        AgreementItemTmfVO agreementItemTmfVO = new AgreementItemTmfVO()
1✔
54
                .addProductItem(
1✔
55
                        new ProductRefTmfVO()
56
                                .id(productOrderId))
1✔
57
                .addProductOfferingItem(
1✔
58
                        new ProductOfferingRefTmfVO()
59
                                .id(productOfferingId));
1✔
60
        CharacteristicTmfVO characteristicTmfVO = new CharacteristicTmfVO()
1✔
61
                .name(DATA_SPACE_PROTOCOL_AGREEMENT_ID)
1✔
62
                .value(agreementId);
1✔
63
        AgreementCreateTmfVO agreementCreateTmfVO = new AgreementCreateTmfVO()
1✔
64
                .characteristic(List.of(characteristicTmfVO))
1✔
65
                .engagedParty(relatedParties)
1✔
66
                // prevent empty refs
67
                .agreementSpecification(null)
1✔
68
                .addAgreementItemItem(agreementItemTmfVO);
1✔
69

70
        return agreementApiClient
1✔
71
                .createAgreement(agreementCreateTmfVO)
1✔
72
                .map(HttpResponse::body)
1✔
73
                .map(AgreementTmfVO::getId)
1✔
74
                .onErrorMap(t -> {
1✔
75
                    log.warn("Was not able to create aggreement", t);
1✔
76
                    throw new TMForumException("Was not able to create agreement", t);
1✔
77
                });
78
    }
79

80

81
    /**
82
     * Add the id of agreements(from rainbow) to the given product order
83
     */
84
    public Mono<ProductOrderVO> addAgreementToOrder(String productOrderId, List<String> agreementIds) {
85
        List<AgreementRefVO> agreementRefVOS = agreementIds.stream()
1✔
86
                .map(id -> new AgreementRefVO().id(id))
1✔
87
                .toList();
1✔
88
        ProductOrderUpdateVO productOrderUpdateVO = new ProductOrderUpdateVO().agreement(agreementRefVOS);
1✔
89
        return productOrderApiClient
1✔
90
                .patchProductOrder(productOrderId, productOrderUpdateVO)
1✔
91
                .map(HttpResponse::body)
1✔
92
                .onErrorMap(t -> {
1✔
93
                    log.warn("Was not able to update the product order {}", productOrderId, t);
1✔
94
                    throw new TMForumException("Was not able to update the product order");
1✔
95
                });
96
    }
97

98
    /**
99
     * Update the externalId of a quote.
100
     */
101
    public Mono<QuoteVO> updateExternalId(QuoteVO quoteVO, String externalId) {
NEW
102
        QuoteUpdateVO quoteUpdateVO = objectMapper.convertValue(quoteVO.externalId(externalId), QuoteUpdateVO.class);
×
103
        // remove the quote object
NEW
104
        quoteUpdateVO.setUnknownProperties("id", null);
×
NEW
105
        quoteUpdateVO.setUnknownProperties("href", null);
×
NEW
106
        quoteUpdateVO.setUnknownProperties("quoteDate", null);
×
107

NEW
108
        return quoteApiClient.patchQuote(quoteVO.getId(), quoteUpdateVO)
×
NEW
109
                .onErrorMap(t -> {
×
NEW
110
                    log.warn("Was not able to update the quote", t);
×
NEW
111
                    throw new TMForumException(String.format("Was not able to update the quote %s.", quoteVO.getId()), t);
×
112
                })
NEW
113
                .map(HttpResponse::body);
×
114
    }
115

116
    /**
117
     * Return the quote with the given id.
118
     */
119
    public Mono<QuoteVO> getQuoteById(String id) {
NEW
120
        return quoteApiClient.retrieveQuote(id, null)
×
NEW
121
                .onErrorMap(t -> {
×
NEW
122
                    throw new TMForumException(String.format("Was not able to get the quote %s.", id), t);
×
123
                })
NEW
124
                .map(HttpResponse::body);
×
125
    }
126

127
    public Mono<ProductSpecificationVO> getSpecFromOfferRef(String refId) {
NEW
128
        return productOfferingApiClient.retrieveProductOffering(refId, null)
×
NEW
129
                .onErrorMap(t -> new TMForumException(String.format("Was not able to retrieve offering %s", refId), t))
×
NEW
130
                .map(HttpResponse::body)
×
NEW
131
                .map(ProductOfferingVO::getProductSpecification)
×
NEW
132
                .map(ProductSpecificationRefVO::getId)
×
NEW
133
                .flatMap(id -> productSpecificationApiClient.retrieveProductSpecification(id, null))
×
NEW
134
                .onErrorMap(t -> new TMForumException(String.format("Was not able to retrieve specification for offering %s", refId), t))
×
NEW
135
                .map(HttpResponse::body);
×
136
    }
137

138

139
    public Mono<String> getConsumerDid(QuoteVO quoteVO) {
NEW
140
        return organizationResolver.getDID(getConsumerIdFromQuote(quoteVO));
×
141
    }
142

143

144
    public String getConsumerIdFromQuote(QuoteVO quoteVO) {
NEW
145
        if (quoteVO.getRelatedParty() == null || quoteVO.getRelatedParty().isEmpty()) {
×
NEW
146
            throw new TMForumException(String.format("Quote %s does not have valid consumer.", quoteVO.getId()));
×
147
        }
NEW
148
        return quoteVO.getRelatedParty()
×
NEW
149
                .stream()
×
NEW
150
                .filter(rp -> rp.getRole().equals(CONSUMER_ROLE))
×
NEW
151
                .findFirst()
×
NEW
152
                .map(org.fiware.iam.tmforum.quote.model.RelatedPartyVO::getId)
×
NEW
153
                .orElseThrow(() -> new TMForumException(String.format("Quote %s does not have valid consumer.", quoteVO.getId())));
×
154
    }
155

156
    public Mono<OfferingParameters> getOfferingParameters(String offeringId) {
NEW
157
        return getSpecFromOfferRef(offeringId)
×
NEW
158
                .map(spec -> fromProductSpecChars(spec.getProductSpecCharacteristic()));
×
159
    }
160

161
    private OfferingParameters fromProductSpecChars(List<ProductSpecificationCharacteristicVO> specChars) {
NEW
162
        String target = "";
×
NEW
163
        String action = "";
×
164

NEW
165
        for (ProductSpecificationCharacteristicVO specChar : specChars) {
×
NEW
166
            if (specChar.getValueType().equals(ProductOfferingConstants.ENDPOINT_URL_TYPE)) {
×
NEW
167
                target = specChar.getProductSpecCharacteristicValue()
×
NEW
168
                        .stream()
×
NEW
169
                        .filter(CharacteristicValueSpecificationVO::getIsDefault)
×
NEW
170
                        .map(CharacteristicValueSpecificationVO::getValue)
×
NEW
171
                        .map(String.class::cast)
×
NEW
172
                        .findAny()
×
NEW
173
                        .orElseThrow(() -> new TMForumException("Was not able to retrieve endpoint from spec."));
×
NEW
174
                continue;
×
175
            }
NEW
176
            if (specChar.getValueType().equals(ProductOfferingConstants.ALLOWED_ACTION_TYPE)) {
×
NEW
177
                action = specChar.getProductSpecCharacteristicValue()
×
NEW
178
                        .stream()
×
NEW
179
                        .filter(CharacteristicValueSpecificationVO::getIsDefault)
×
NEW
180
                        .map(CharacteristicValueSpecificationVO::getValue)
×
NEW
181
                        .map(String.class::cast)
×
NEW
182
                        .findAny()
×
NEW
183
                        .orElseThrow(() -> new TMForumException("Was not able to retrieve action from spec."));
×
184
            }
NEW
185
        }
×
NEW
186
        if (action.isEmpty() || target.isEmpty()) {
×
NEW
187
            throw new TMForumException(String.format("Was not able to get valid action %s and/or target %s.", action, target));
×
188
        }
NEW
189
        return new OfferingParameters(target, action);
×
190
    }
191

192

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