Skip to content

Commit 9d6e72a

Browse files
authored
SSPBC Adapter: adapter update (#4135)
1 parent a22c6b7 commit 9d6e72a

9 files changed

Lines changed: 154 additions & 625 deletions

File tree

Lines changed: 39 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,34 @@
11
package org.prebid.server.bidder.sspbc;
22

3-
import com.fasterxml.jackson.core.type.TypeReference;
4-
import com.fasterxml.jackson.databind.JsonNode;
5-
import com.fasterxml.jackson.databind.node.ObjectNode;
6-
import com.iab.openrtb.request.Banner;
73
import com.iab.openrtb.request.BidRequest;
8-
import com.iab.openrtb.request.Format;
9-
import com.iab.openrtb.request.Imp;
10-
import com.iab.openrtb.request.Site;
114
import com.iab.openrtb.response.Bid;
125
import com.iab.openrtb.response.BidResponse;
136
import com.iab.openrtb.response.SeatBid;
7+
import io.vertx.core.http.HttpMethod;
148
import org.apache.commons.collections4.CollectionUtils;
15-
import org.apache.commons.lang3.StringUtils;
169
import org.apache.http.client.utils.URIBuilder;
1710
import org.prebid.server.bidder.Bidder;
1811
import org.prebid.server.bidder.model.BidderBid;
1912
import org.prebid.server.bidder.model.BidderCall;
2013
import org.prebid.server.bidder.model.BidderError;
2114
import org.prebid.server.bidder.model.HttpRequest;
2215
import org.prebid.server.bidder.model.Result;
23-
import org.prebid.server.bidder.sspbc.request.SspbcRequestType;
2416
import org.prebid.server.exception.PreBidException;
2517
import org.prebid.server.json.DecodeException;
2618
import org.prebid.server.json.JacksonMapper;
27-
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
28-
import org.prebid.server.proto.openrtb.ext.request.sspbc.ExtImpSspbc;
2919
import org.prebid.server.proto.openrtb.ext.response.BidType;
3020
import org.prebid.server.util.BidderUtil;
3121
import org.prebid.server.util.HttpUtil;
32-
import org.prebid.server.util.ObjectUtil;
3322

3423
import java.net.URISyntaxException;
35-
import java.util.ArrayList;
24+
import java.util.Collection;
3625
import java.util.Collections;
37-
import java.util.Comparator;
3826
import java.util.List;
39-
import java.util.Map;
4027
import java.util.Objects;
41-
import java.util.Optional;
42-
import java.util.function.Function;
43-
import java.util.function.UnaryOperator;
44-
import java.util.stream.Collectors;
4528

46-
public class SspbcBidder implements Bidder<BidRequest> {
29+
public class SspbcBidder implements Bidder<SspbcRequest> {
4730

48-
private static final TypeReference<ExtPrebid<?, ExtImpSspbc>> SSPBC_EXT_TYPE_REFERENCE =
49-
new TypeReference<>() {
50-
};
51-
private static final String ADAPTER_VERSION = "5.8";
52-
private static final String IMP_FALLBACK_SIZE = "1x1";
53-
private static final String PREBID_SERVER_INTEGRATION_TYPE = "4";
54-
private static final String BANNER_TEMPLATE = """
55-
<html><head><title></title><meta charset="UTF-8"><meta name="viewport"\
56-
content="width=device-width, initial-scale=1.0"><style> body { background-color:\
57-
transparent; margin: 0; padding: 0; }</style><script> window.rekid = {{.SiteId}};\
58-
window.slot = {{.SlotId}}; window.adlabel = '{{.AdLabel}}'; window.pubid = '{{.PubId}}';\
59-
window.wp_sn = 'sspbc_go'; window.page = '{{.Page}}'; window.ref = '{{.Referer}}';\
60-
window.mcad = {{.McAd}}; window.inver = '{{.Inver}}'; </script></head><body><div id="c"></div><script\
61-
async crossorigin nomodule src="//std.wpcdn.pl/wpjslib/wpjslib-inline.js"\
62-
id="wpjslib"></script><script async crossorigin type="module"\
63-
src="//std.wpcdn.pl/wpjslib6/wpjslib-inline.js" id="wpjslib6"></script></body></html>""";
31+
private static final String ADAPTER_VERSION = "6.0";
6432

6533
private final String endpointUrl;
6634
private final JacksonMapper mapper;
@@ -71,247 +39,66 @@ public SspbcBidder(String endpointUrl, JacksonMapper mapper) {
7139
}
7240

7341
@Override
74-
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
75-
if (request.getSite() == null) {
76-
return Result.withError(BidderError.badInput("BidRequest.site not provided"));
77-
}
78-
79-
final Map<Imp, ExtImpSspbc> impToExt;
80-
81-
try {
82-
impToExt = createImpToExt(request);
83-
} catch (PreBidException e) {
84-
return Result.withError(BidderError.badInput(e.getMessage()));
85-
}
86-
87-
final SspbcRequestType requestType = getRequestType(impToExt);
88-
final List<Imp> imps = new ArrayList<>();
89-
String siteId = "";
90-
91-
for (Imp imp : request.getImp()) {
92-
final ExtImpSspbc extImpSspbc = impToExt.get(imp);
93-
final String extImpSspbcSiteId = extImpSspbc.getSiteId();
94-
if (StringUtils.isNotEmpty(extImpSspbcSiteId)) {
95-
siteId = extImpSspbcSiteId;
96-
}
97-
98-
imps.add(updateImp(imp, requestType, extImpSspbc));
99-
}
100-
101-
try {
102-
return Result.withValue(createRequest(updateBidRequest(request, imps, requestType, siteId)));
103-
} catch (PreBidException e) {
104-
return Result.withError(BidderError.badInput(e.getMessage()));
105-
}
106-
}
107-
108-
private Map<Imp, ExtImpSspbc> createImpToExt(BidRequest request) {
109-
return request.getImp()
110-
.stream()
111-
.collect(Collectors.toMap(Function.identity(), this::parseImpExt));
112-
}
113-
114-
private ExtImpSspbc parseImpExt(Imp imp) {
115-
try {
116-
return mapper.mapper().convertValue(imp.getExt(), SSPBC_EXT_TYPE_REFERENCE).getBidder();
117-
} catch (IllegalArgumentException e) {
118-
throw new PreBidException(e.getMessage());
119-
}
120-
}
121-
122-
private Imp updateImp(Imp imp, SspbcRequestType requestType, ExtImpSspbc extImpSspbc) {
123-
final String originalImpId = imp.getId();
124-
125-
return imp.toBuilder()
126-
.id(resolveImpId(originalImpId, extImpSspbc.getId(), requestType))
127-
.tagid(originalImpId)
128-
.ext(createImpExt(imp))
42+
public Result<List<HttpRequest<SspbcRequest>>> makeHttpRequests(BidRequest request) {
43+
return Result.withValue(createHttpRequest(request));
44+
}
45+
46+
private HttpRequest<SspbcRequest> createHttpRequest(BidRequest request) {
47+
final SspbcRequest outgoingRequest = SspbcRequest.of(request);
48+
return HttpRequest.<SspbcRequest>builder()
49+
.method(HttpMethod.POST)
50+
.uri(makeUrl(endpointUrl))
51+
.headers(HttpUtil.headers())
52+
.impIds(BidderUtil.impIds(outgoingRequest.getBidRequest()))
53+
.body(mapper.encodeToBytes(outgoingRequest))
54+
.payload(outgoingRequest)
12955
.build();
13056
}
13157

132-
private String resolveImpId(String originalImpId, String extImpId, SspbcRequestType requestType) {
133-
return StringUtils.isNotEmpty(extImpId) && requestType != SspbcRequestType.REQUEST_TYPE_ONE_CODE
134-
? extImpId
135-
: originalImpId;
136-
}
137-
138-
private ObjectNode createImpExt(Imp imp) {
139-
return mapper.mapper().createObjectNode()
140-
.set("data", mapper.mapper().createObjectNode()
141-
.put("pbslot", imp.getTagid())
142-
.put("pbsize", getImpSize(imp)));
143-
}
144-
145-
private BidRequest updateBidRequest(BidRequest bidRequest,
146-
List<Imp> imps,
147-
SspbcRequestType requestType,
148-
String siteId) {
149-
150-
return bidRequest.toBuilder()
151-
.imp(imps)
152-
.site(updateSite(bidRequest.getSite(), requestType, siteId))
153-
.test(updateTest(requestType, bidRequest.getTest()))
154-
.build();
155-
}
156-
157-
private Site updateSite(Site site, SspbcRequestType requestType, String siteId) {
158-
return site.toBuilder()
159-
.id(resolveSiteId(requestType, siteId))
160-
.domain(getUri(site.getPage()).getHost())
161-
.build();
162-
}
163-
164-
private static String resolveSiteId(SspbcRequestType requestType, String siteId) {
165-
return requestType == SspbcRequestType.REQUEST_TYPE_ONE_CODE || StringUtils.isBlank(siteId)
166-
? StringUtils.EMPTY
167-
: siteId;
168-
}
169-
170-
private static Integer updateTest(SspbcRequestType requestType, Integer test) {
171-
return requestType == SspbcRequestType.REQUEST_TYPE_TEST ? 1 : test;
172-
}
173-
174-
private String getImpSize(Imp imp) {
175-
final List<Format> formats = ObjectUtil.getIfNotNull(imp.getBanner(), Banner::getFormat);
176-
if (CollectionUtils.isEmpty(formats)) {
177-
return IMP_FALLBACK_SIZE;
178-
}
179-
180-
return formats.stream()
181-
.max(Comparator.comparing(SspbcBidder::formatToArea))
182-
.filter(format -> formatToArea(format) > 0)
183-
.map(format -> String.format("%dx%d", format.getW(), format.getH()))
184-
.orElse(IMP_FALLBACK_SIZE);
185-
}
186-
187-
private static int formatToArea(Format format) {
188-
final Integer w = ObjectUtil.getIfNotNull(format, Format::getW);
189-
final Integer h = ObjectUtil.getIfNotNull(format, Format::getH);
190-
191-
return w != null && h != null ? w * h : 0;
192-
}
193-
194-
private SspbcRequestType getRequestType(Map<Imp, ExtImpSspbc> impToExt) {
195-
for (ExtImpSspbc extImpSspbc : impToExt.values()) {
196-
if (extImpSspbc.getTest() != 0) {
197-
return SspbcRequestType.REQUEST_TYPE_TEST;
198-
}
199-
200-
if (StringUtils.isAnyEmpty(extImpSspbc.getSiteId(), extImpSspbc.getId())) {
201-
return SspbcRequestType.REQUEST_TYPE_ONE_CODE;
202-
}
203-
}
204-
205-
return SspbcRequestType.REQUEST_TYPE_STANDARD;
206-
}
207-
208-
private HttpRequest<BidRequest> createRequest(BidRequest request) {
209-
return BidderUtil.defaultRequest(request, updateUrl(getUri(endpointUrl)), mapper);
210-
}
211-
212-
private static URIBuilder getUri(String endpointUrl) {
213-
final URIBuilder uri;
58+
private static String makeUrl(String endpointUrl) {
21459
try {
215-
uri = new URIBuilder(endpointUrl);
60+
return new URIBuilder(endpointUrl)
61+
.addParameter("bdver", ADAPTER_VERSION)
62+
.build()
63+
.toString();
21664
} catch (URISyntaxException e) {
21765
throw new PreBidException("Malformed URL: %s.".formatted(endpointUrl));
21866
}
219-
return uri;
220-
}
221-
222-
private String updateUrl(URIBuilder uriBuilder) {
223-
return uriBuilder
224-
.addParameter("bdver", ADAPTER_VERSION)
225-
.addParameter("inver", PREBID_SERVER_INTEGRATION_TYPE)
226-
.toString();
22767
}
22868

22969
@Override
230-
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
70+
public Result<List<BidderBid>> makeBids(BidderCall<SspbcRequest> httpCall, BidRequest bidRequest) {
23171
try {
23272
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
233-
return Result.withValues(extractBids(bidResponse, httpCall.getRequest().getPayload()));
73+
return Result.withValues(extractBids(bidResponse));
23474
} catch (PreBidException | DecodeException e) {
23575
return Result.withError(BidderError.badServerResponse(e.getMessage()));
23676
}
23777
}
23878

239-
private List<BidderBid> extractBids(BidResponse bidResponse, BidRequest bidRequest) {
79+
private List<BidderBid> extractBids(BidResponse bidResponse) {
24080
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
24181
return Collections.emptyList();
24282
}
24383

24484
return bidResponse.getSeatbid().stream()
24585
.filter(Objects::nonNull)
246-
.map(seatBid -> CollectionUtils.emptyIfNull(seatBid.getBid())
247-
.stream()
248-
.filter(Objects::nonNull)
249-
.map(bid -> toBidderBid(bid, seatBid.getSeat(), bidResponse.getCur(), bidRequest)))
250-
.flatMap(UnaryOperator.identity())
86+
.map(SeatBid::getBid)
87+
.filter(Objects::nonNull)
88+
.flatMap(Collection::stream)
89+
.filter(Objects::nonNull)
90+
.map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur()))
25191
.toList();
25292
}
25393

254-
private BidderBid toBidderBid(Bid bid, String seat, String currency, BidRequest bidRequest) {
255-
if (StringUtils.isEmpty(bid.getAdm())) {
256-
throw new PreBidException("Bid format is not supported");
257-
}
258-
259-
final ObjectNode bidExt = bid.getExt();
260-
final Bid updatedBid = bid.toBuilder()
261-
.impid(getImpTagId(bidRequest.getImp(), bid))
262-
.adm(createBannerAd(
263-
bid,
264-
stringOrNull(bidExt, "adlabel"),
265-
stringOrNull(bidExt, "pubid"),
266-
stringOrNull(bidExt, "siteid"),
267-
stringOrNull(bidExt, "slotid"),
268-
seat,
269-
bidRequest))
270-
.build();
271-
272-
return BidderBid.of(updatedBid, BidType.banner, currency);
273-
}
274-
275-
private static String stringOrNull(ObjectNode bidExt, String property) {
276-
return Optional.ofNullable(bidExt)
277-
.map(ext -> ext.get(property))
278-
.map(JsonNode::asText)
279-
.orElse(StringUtils.EMPTY);
280-
}
281-
282-
private static String getImpTagId(List<Imp> imps, Bid bid) {
283-
return imps.stream()
284-
.filter(imp -> Objects.equals(imp.getId(), bid.getImpid()))
285-
.map(Imp::getTagid)
286-
.findAny()
287-
.orElseThrow(() -> new PreBidException("imp not found"));
288-
}
289-
290-
private String createBannerAd(Bid bid,
291-
String adlabel,
292-
String pubid,
293-
String siteid,
294-
String slotid,
295-
String seat,
296-
BidRequest bidRequest) {
297-
if (bid.getAdm().contains("<!--preformatted-->")) {
298-
return bid.getAdm();
299-
}
300-
301-
final ObjectNode mcad = mapper.mapper().createObjectNode()
302-
.put("id", bidRequest.getId())
303-
.put("seat", seat)
304-
.set("seatbid", mapper.mapper()
305-
.convertValue(SeatBid.builder().bid(Collections.singletonList(bid)).build(), JsonNode.class));
306-
307-
return BANNER_TEMPLATE
308-
.replace("{{.SiteId}}", siteid)
309-
.replace("{{.SlotId}}", slotid)
310-
.replace("{{.AdLabel}}", adlabel)
311-
.replace("{{.PubId}}", pubid)
312-
.replace("{{.Page}}", bidRequest.getSite().getPage())
313-
.replace("{{.Referer}}", bidRequest.getSite().getRef())
314-
.replace("{{.McAd}}", mcad.toString())
315-
.replace("{{.Inver}}", PREBID_SERVER_INTEGRATION_TYPE);
94+
private static BidType getBidType(Bid bid) {
95+
return switch (bid.getMtype()) {
96+
case 1 -> BidType.banner;
97+
case 2 -> BidType.video;
98+
case 3 -> BidType.audio;
99+
case 4 -> BidType.xNative;
100+
case null -> throw new PreBidException("Bid mtype is required");
101+
default -> throw new PreBidException("unsupported MType: %s.".formatted(bid.getMtype()));
102+
};
316103
}
317104
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.prebid.server.bidder.sspbc;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.iab.openrtb.request.BidRequest;
5+
import lombok.Value;
6+
7+
@Value(staticConstructor = "of")
8+
public class SspbcRequest {
9+
10+
@JsonProperty("bidRequest")
11+
BidRequest bidRequest;
12+
}

src/main/java/org/prebid/server/bidder/sspbc/request/SspbcRequestType.java

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)