Skip to content

Commit 4323ae8

Browse files
Rubicon Adapter: Set RendererUrl Metadata (#3682)
1 parent b82fdd2 commit 4323ae8

File tree

5 files changed

+427
-57
lines changed

5 files changed

+427
-57
lines changed

src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java

Lines changed: 105 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ public class RubiconBidder implements Bidder<BidRequest> {
186186
private final String xapiUsername;
187187
private final Set<String> supportedVendors;
188188
private final boolean generateBidId;
189+
private final String apexRendererUrl;
189190
private final CurrencyConversionService currencyConversionService;
190191
private final PriceFloorResolver floorResolver;
191192
private final PrebidVersionProvider versionProvider;
@@ -200,6 +201,7 @@ public RubiconBidder(String bidderName,
200201
String xapiPassword,
201202
List<String> supportedVendors,
202203
boolean generateBidId,
204+
String apexRendererUrl,
203205
CurrencyConversionService currencyConversionService,
204206
PriceFloorResolver floorResolver,
205207
PrebidVersionProvider versionProvider,
@@ -211,6 +213,7 @@ public RubiconBidder(String bidderName,
211213
this.xapiUsername = Objects.requireNonNull(xapiUsername);
212214
this.supportedVendors = Set.copyOf(Objects.requireNonNull(supportedVendors));
213215
this.generateBidId = generateBidId;
216+
this.apexRendererUrl = apexRendererUrl;
214217
this.currencyConversionService = Objects.requireNonNull(currencyConversionService);
215218
this.floorResolver = Objects.requireNonNull(floorResolver);
216219
this.versionProvider = Objects.requireNonNull(versionProvider);
@@ -1565,58 +1568,104 @@ private List<BidderBid> bidsFromResponse(BidRequest prebidRequest,
15651568
.collect(Collectors.toMap(Imp::getId, Function.identity()));
15661569
final Map<String, Imp> idToRubiconImp = bidRequest.getImp().stream()
15671570
.collect(Collectors.toMap(Imp::getId, Function.identity()));
1568-
final Float cpmOverrideFromRequest = cpmOverrideFromRequest(prebidRequest);
1571+
final RubiconExtPrebidBiddersBidder extPrebidBiddersBidder = extPrebidBiddersRubicon(prebidRequest.getExt());
1572+
final Float cpmOverrideFromRequest = cpmOverrideFromRequest(extPrebidBiddersBidder);
1573+
final boolean hasApexRenderer = hasApexRenderer(extPrebidBiddersBidder);
15691574
final BidType bidType = bidType(bidRequest);
15701575

15711576
return bidResponse.getSeatbid().stream()
15721577
.filter(Objects::nonNull)
1573-
.map(seatBid -> updateSeatBids(seatBid, errors))
1574-
.map(RubiconSeatBid::getBid)
1575-
.filter(Objects::nonNull)
1578+
.map(seatBid -> seatBid.getBid().stream()
1579+
.filter(Objects::nonNull)
1580+
.map(bid -> updateBid(
1581+
bid,
1582+
seatBid,
1583+
idToImp.get(bid.getImpid()),
1584+
bidType,
1585+
cpmOverrideFromRequest,
1586+
hasApexRenderer,
1587+
bidResponse,
1588+
errors))
1589+
.filter(Objects::nonNull)
1590+
.map(bid -> createBidderBid(
1591+
bid,
1592+
idToRubiconImp.get(bid.getImpid()),
1593+
bidType,
1594+
bidResponse.getCur()))
1595+
.toList())
15761596
.flatMap(Collection::stream)
1577-
.map(bid -> updateBid(bid, idToImp.get(bid.getImpid()), cpmOverrideFromRequest, bidResponse))
1578-
.map(bid -> createBidderBid(bid, idToRubiconImp.get(bid.getImpid()), bidType, bidResponse.getCur()))
15791597
.toList();
15801598
}
15811599

1582-
private RubiconSeatBid updateSeatBids(RubiconSeatBid seatBid, List<BidderError> errors) {
1583-
final Integer networkId = resolveNetworkId(seatBid);
1584-
final String seat = seatBid.getSeat();
1600+
private Bid updateBid(RubiconBid bid,
1601+
RubiconSeatBid seatBid,
1602+
Imp imp,
1603+
BidType bidType,
1604+
Float cpmOverrideFromRequest,
1605+
boolean hasApexRenderer,
1606+
RubiconBidResponse bidResponse,
1607+
List<BidderError> errors) {
15851608

1586-
if (networkId == null && seat == null) {
1587-
return seatBid;
1609+
final ObjectNode updateBidExt;
1610+
try {
1611+
updateBidExt = prepareBidExt(bid, seatBid, imp, bidType, hasApexRenderer);
1612+
} catch (PreBidException e) {
1613+
errors.add(BidderError.badServerResponse(e.getMessage()));
1614+
return null;
15881615
}
15891616

1590-
final List<RubiconBid> updatedBids = seatBid.getBid().stream()
1591-
.map(bid -> prepareBidMeta(bid, seat, networkId, errors))
1592-
.filter(Objects::nonNull)
1593-
.toList();
1594-
return seatBid.toBuilder().bid(updatedBids).build();
1595-
}
1617+
String bidId = bid.getId();
1618+
if (generateBidId) {
1619+
// Since Rubicon XAPI returns openrtb_response.seatbid.bid.id not unique enough
1620+
// generate new value for it
1621+
bidId = UUID.randomUUID().toString();
1622+
} else if (Objects.equals(bid.getId(), "0")) {
1623+
// Since Rubicon XAPI returns only one bid per response
1624+
// copy bidResponse.bidid to openrtb_response.seatbid.bid.id
1625+
bidId = bidResponse.getBidid();
1626+
}
15961627

1597-
private static Integer resolveNetworkId(RubiconSeatBid seatBid) {
1598-
final String buyer = seatBid.getBuyer();
1599-
final int networkId = NumberUtils.toInt(buyer, 0);
1600-
return networkId <= 0 ? null : networkId;
1628+
// Unconditionally set price if coming from CPM override
1629+
final Float cpmOverride = ObjectUtils.defaultIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest);
1630+
final BigDecimal bidPrice = cpmOverride != null
1631+
? new BigDecimal(String.valueOf(cpmOverride))
1632+
: bid.getPrice();
1633+
1634+
final RubiconBid updatedRubiconBid = bid.toBuilder()
1635+
.id(bidId)
1636+
.adm(resolveAdm(bid.getAdm(), bid.getAdmNative()))
1637+
.price(bidPrice)
1638+
.ext(updateBidExt)
1639+
.build();
1640+
1641+
return bidFromRubiconBid(updatedRubiconBid);
16011642
}
16021643

1603-
private RubiconBid prepareBidMeta(RubiconBid bid, String seat, Integer networkId, List<BidderError> errors) {
1644+
private ObjectNode prepareBidExt(RubiconBid bid,
1645+
RubiconSeatBid seatBid,
1646+
Imp imp,
1647+
BidType bidType,
1648+
boolean hasApexRenderer) {
1649+
16041650
final ObjectNode bidExt = bid.getExt();
1605-
final ExtPrebid<ExtBidPrebid, ObjectNode> extPrebid;
1606-
try {
1607-
extPrebid = getExtPrebid(bidExt, bid.getId());
1608-
} catch (PreBidException e) {
1609-
errors.add(BidderError.badServerResponse(e.getMessage()));
1610-
return null;
1611-
}
1651+
final ExtPrebid<ExtBidPrebid, ObjectNode> extPrebid = getExtPrebid(bidExt, bid.getId());
16121652
final ExtBidPrebid extBidPrebid = extPrebid != null ? extPrebid.getPrebid() : null;
16131653
final ExtBidPrebidMeta meta = extBidPrebid != null ? extBidPrebid.getMeta() : null;
16141654

1655+
final Integer networkId = resolveNetworkId(seatBid);
1656+
final String seat = seatBid.getSeat();
1657+
final String rendererUrl = resolveRendererUrl(imp, meta, bidType, hasApexRenderer);
1658+
1659+
if (ObjectUtils.allNull(networkId, rendererUrl, seat)) {
1660+
return bidExt;
1661+
}
1662+
16151663
final ExtBidPrebidMeta updatedMeta = Optional.ofNullable(meta)
16161664
.map(ExtBidPrebidMeta::toBuilder)
16171665
.orElseGet(ExtBidPrebidMeta::builder)
16181666
.networkId(networkId)
16191667
.seat(seat)
1668+
.rendererUrl(rendererUrl)
16201669
.build();
16211670

16221671
final ExtBidPrebid modifiedExtBidPrebid = extBidPrebid != null
@@ -1626,7 +1675,7 @@ private RubiconBid prepareBidMeta(RubiconBid bid, String seat, Integer networkId
16261675
final ObjectNode updatedBidExt = bidExt != null ? bidExt : mapper.mapper().createObjectNode();
16271676
updatedBidExt.set(PREBID_EXT, mapper.mapper().valueToTree(modifiedExtBidPrebid));
16281677

1629-
return bid.toBuilder().ext(updatedBidExt).build();
1678+
return updatedBidExt;
16301679
}
16311680

16321681
private ExtPrebid<ExtBidPrebid, ObjectNode> getExtPrebid(ObjectNode bidExt, String bidId) {
@@ -1637,31 +1686,30 @@ private ExtPrebid<ExtBidPrebid, ObjectNode> getExtPrebid(ObjectNode bidExt, Stri
16371686
}
16381687
}
16391688

1640-
private Bid updateBid(RubiconBid bid, Imp imp, Float cpmOverrideFromRequest, RubiconBidResponse bidResponse) {
1641-
String bidId = bid.getId();
1642-
if (generateBidId) {
1643-
// Since Rubicon XAPI returns openrtb_response.seatbid.bid.id not unique enough
1644-
// generate new value for it
1645-
bidId = UUID.randomUUID().toString();
1646-
} else if (Objects.equals(bid.getId(), "0")) {
1647-
// Since Rubicon XAPI returns only one bid per response
1648-
// copy bidResponse.bidid to openrtb_response.seatbid.bid.id
1649-
bidId = bidResponse.getBidid();
1650-
}
1689+
private static Integer resolveNetworkId(RubiconSeatBid seatBid) {
1690+
final String buyer = seatBid.getBuyer();
1691+
final int networkId = NumberUtils.toInt(buyer, 0);
1692+
return networkId <= 0 ? null : networkId;
1693+
}
16511694

1652-
// Unconditionally set price if coming from CPM override
1653-
final Float cpmOverride = ObjectUtils.defaultIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest);
1654-
final BigDecimal bidPrice = cpmOverride != null
1655-
? new BigDecimal(String.valueOf(cpmOverride))
1656-
: bid.getPrice();
1695+
private String resolveRendererUrl(Imp imp, ExtBidPrebidMeta meta, BidType bidType, boolean hasApexRenderer) {
1696+
if (imp == null) {
1697+
return null;
1698+
}
16571699

1658-
final RubiconBid updatedRubiconBid = bid.toBuilder()
1659-
.id(bidId)
1660-
.adm(resolveAdm(bid.getAdm(), bid.getAdmNative()))
1661-
.price(bidPrice)
1662-
.build();
1700+
final Video video = imp.getVideo();
1701+
return hasApexRenderer
1702+
&& (bidType == BidType.video || isVideoMetaMediaType(meta))
1703+
&& (video != null && !Objects.equals(video.getPlacement(), 1) && !Objects.equals(video.getPlcmt(), 1))
1704+
? apexRendererUrl
1705+
: null;
1706+
}
16631707

1664-
return bidFromRubiconBid(updatedRubiconBid);
1708+
private static Boolean isVideoMetaMediaType(ExtBidPrebidMeta meta) {
1709+
return Optional.ofNullable(meta)
1710+
.map(ExtBidPrebidMeta::getMediaType)
1711+
.map("video"::equalsIgnoreCase)
1712+
.orElse(false);
16651713
}
16661714

16671715
private String resolveAdm(String bidAdm, ObjectNode admobject) {
@@ -1681,7 +1729,6 @@ private Bid bidFromRubiconBid(RubiconBid rubiconBid) {
16811729
}
16821730

16831731
private static BidderBid createBidderBid(Bid bid, Imp imp, BidType bidType, String currency) {
1684-
16851732
return BidderBid.builder()
16861733
.bid(bid)
16871734
.type(bidType)
@@ -1690,8 +1737,7 @@ private static BidderBid createBidderBid(Bid bid, Imp imp, BidType bidType, Stri
16901737
.build();
16911738
}
16921739

1693-
private Float cpmOverrideFromRequest(BidRequest bidRequest) {
1694-
final RubiconExtPrebidBiddersBidder bidder = extPrebidBiddersRubicon(bidRequest.getExt());
1740+
private static Float cpmOverrideFromRequest(RubiconExtPrebidBiddersBidder bidder) {
16951741
final RubiconExtPrebidBiddersBidderDebug debug = bidder != null ? bidder.getDebug() : null;
16961742
return debug != null ? debug.getCpmoverride() : null;
16971743
}
@@ -1704,6 +1750,10 @@ private Float cpmOverrideFromImp(Imp imp) {
17041750
.orElse(null);
17051751
}
17061752

1753+
private static boolean hasApexRenderer(RubiconExtPrebidBiddersBidder bidder) {
1754+
return Optional.ofNullable(bidder).map(RubiconExtPrebidBiddersBidder::getApexRenderer).orElse(false);
1755+
}
1756+
17071757
private static BidType bidType(BidRequest bidRequest) {
17081758
final ImpMediaType impMediaType = impType(bidRequest.getImp().getFirst());
17091759
return switch (impMediaType) {

src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconExtPrebidBiddersBidder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.prebid.server.bidder.rubicon.proto.request;
22

3+
import com.fasterxml.jackson.annotation.JsonProperty;
34
import lombok.AllArgsConstructor;
45
import lombok.Value;
56

@@ -10,4 +11,7 @@ public class RubiconExtPrebidBiddersBidder {
1011
String integration;
1112

1213
RubiconExtPrebidBiddersBidderDebug debug;
14+
15+
@JsonProperty("apexRenderer")
16+
Boolean apexRenderer;
1317
}

src/main/java/org/prebid/server/spring/config/bidder/RubiconConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ BidderDeps rubiconBidderDeps(RubiconConfigurationProperties rubiconConfiguration
5656
config.getXapi().getPassword(),
5757
config.getMetaInfo().getSupportedVendors(),
5858
config.getGenerateBidId(),
59+
config.getApexRendererUrl(),
5960
currencyConversionService,
6061
floorResolver,
6162
versionProvider,
@@ -75,6 +76,9 @@ private static class RubiconConfigurationProperties extends BidderConfigurationP
7576

7677
@NotNull
7778
private Boolean generateBidId;
79+
80+
@NotNull
81+
private String apexRendererUrl;
7882
}
7983

8084
@Data

src/main/resources/bidder-config/rubicon.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ adapters:
3838
url: GET_FROM_globalsupport@magnite.com
3939
support-cors: false
4040
generate-bid-id: false
41+
apex-renderer-url: "https://video-outstream.rubiconproject.com/apex-2.2.1.js"
4142
XAPI:
4243
Username: GET_FROM_globalsupport@magnite.com
4344
Password: GET_FROM_globalsupport@magnite.com

0 commit comments

Comments
 (0)