Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rubicon Adapter: Set RendererUrl Metadata #3682

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 103 additions & 55 deletions src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ public class RubiconBidder implements Bidder<BidRequest> {
new TypeReference<>() {
};
private static final boolean DEFAULT_MULTIFORMAT_VALUE = false;
private static final String VIDEO_OUTSTREAM_APEX_META_RENDERER_URL = "https://video-outstream.rubiconproject.com/apex-2.2.1.js";

private final String bidderName;
private final String endpointUrl;
Expand Down Expand Up @@ -1609,58 +1610,104 @@ private List<BidderBid> bidsFromResponse(BidRequest prebidRequest,
.collect(Collectors.toMap(Imp::getId, Function.identity()));
final Map<String, Imp> idToRubiconImp = bidRequest.getImp().stream()
.collect(Collectors.toMap(Imp::getId, Function.identity()));
final Float cpmOverrideFromRequest = cpmOverrideFromRequest(prebidRequest);
final RubiconExtPrebidBiddersBidder extPrebidBiddersBidder = extPrebidBiddersRubicon(prebidRequest.getExt());
final Float cpmOverrideFromRequest = cpmOverrideFromRequest(extPrebidBiddersBidder);
final boolean hasApexRenderer = hasApexRenderer(extPrebidBiddersBidder);
final BidType bidType = bidType(bidRequest);

return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(seatBid -> updateSeatBids(seatBid, errors))
.map(RubiconSeatBid::getBid)
.filter(Objects::nonNull)
.map(seatBid -> seatBid.getBid().stream()
.filter(Objects::nonNull)
.map(bid -> updateBid(
bid,
seatBid,
idToImp.get(bid.getImpid()),
bidType,
cpmOverrideFromRequest,
hasApexRenderer,
bidResponse,
errors))
.filter(Objects::nonNull)
.map(bid -> createBidderBid(
bid,
idToRubiconImp.get(bid.getImpid()),
bidType,
bidResponse.getCur()))
.toList())
.flatMap(Collection::stream)
.map(bid -> updateBid(bid, idToImp.get(bid.getImpid()), cpmOverrideFromRequest, bidResponse))
.map(bid -> createBidderBid(bid, idToRubiconImp.get(bid.getImpid()), bidType, bidResponse.getCur()))
.toList();
}

private RubiconSeatBid updateSeatBids(RubiconSeatBid seatBid, List<BidderError> errors) {
final Integer networkId = resolveNetworkId(seatBid);
final String seat = seatBid.getSeat();
private Bid updateBid(RubiconBid bid,
RubiconSeatBid seatBid,
Imp imp,
BidType bidType,
Float cpmOverrideFromRequest,
boolean hasApexRenderer,
RubiconBidResponse bidResponse,
List<BidderError> errors) {

if (networkId == null && seat == null) {
return seatBid;
final ObjectNode updateBidExt;
try {
updateBidExt = prepareBidExt(bid, seatBid, imp, bidType, hasApexRenderer);
} catch (PreBidException e) {
errors.add(BidderError.badServerResponse(e.getMessage()));
return null;
}

final List<RubiconBid> updatedBids = seatBid.getBid().stream()
.map(bid -> prepareBidMeta(bid, seat, networkId, errors))
.filter(Objects::nonNull)
.toList();
return seatBid.toBuilder().bid(updatedBids).build();
}
String bidId = bid.getId();
if (generateBidId) {
// Since Rubicon XAPI returns openrtb_response.seatbid.bid.id not unique enough
// generate new value for it
bidId = UUID.randomUUID().toString();
} else if (Objects.equals(bid.getId(), "0")) {
// Since Rubicon XAPI returns only one bid per response
// copy bidResponse.bidid to openrtb_response.seatbid.bid.id
bidId = bidResponse.getBidid();
}

private static Integer resolveNetworkId(RubiconSeatBid seatBid) {
final String buyer = seatBid.getBuyer();
final int networkId = NumberUtils.toInt(buyer, 0);
return networkId <= 0 ? null : networkId;
// Unconditionally set price if coming from CPM override
final Float cpmOverride = ObjectUtils.defaultIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest);
final BigDecimal bidPrice = cpmOverride != null
? new BigDecimal(String.valueOf(cpmOverride))
: bid.getPrice();

final RubiconBid updatedRubiconBid = bid.toBuilder()
.id(bidId)
.adm(resolveAdm(bid.getAdm(), bid.getAdmNative()))
.price(bidPrice)
.ext(updateBidExt)
.build();

return bidFromRubiconBid(updatedRubiconBid);
}

private RubiconBid prepareBidMeta(RubiconBid bid, String seat, Integer networkId, List<BidderError> errors) {
private ObjectNode prepareBidExt(RubiconBid bid,
RubiconSeatBid seatBid,
Imp imp,
BidType bidType,
boolean hasApexRenderer) {

final ObjectNode bidExt = bid.getExt();
final ExtPrebid<ExtBidPrebid, ObjectNode> extPrebid;
try {
extPrebid = getExtPrebid(bidExt, bid.getId());
} catch (PreBidException e) {
errors.add(BidderError.badServerResponse(e.getMessage()));
return null;
}
final ExtPrebid<ExtBidPrebid, ObjectNode> extPrebid = getExtPrebid(bidExt, bid.getId());
final ExtBidPrebid extBidPrebid = extPrebid != null ? extPrebid.getPrebid() : null;
final ExtBidPrebidMeta meta = extBidPrebid != null ? extBidPrebid.getMeta() : null;

final Integer networkId = resolveNetworkId(seatBid);
final String seat = seatBid.getSeat();
final String rendererUrl = resolveRendererUrl(imp, meta, bidType, hasApexRenderer);

if (ObjectUtils.allNull(networkId, rendererUrl, seat)) {
return bidExt;
}

final ExtBidPrebidMeta updatedMeta = Optional.ofNullable(meta)
.map(ExtBidPrebidMeta::toBuilder)
.orElseGet(ExtBidPrebidMeta::builder)
.networkId(networkId)
.seat(seat)
.rendererUrl(rendererUrl)
.build();

final ExtBidPrebid modifiedExtBidPrebid = extBidPrebid != null
Expand All @@ -1670,7 +1717,7 @@ private RubiconBid prepareBidMeta(RubiconBid bid, String seat, Integer networkId
final ObjectNode updatedBidExt = bidExt != null ? bidExt : mapper.mapper().createObjectNode();
updatedBidExt.set(PREBID_EXT, mapper.mapper().valueToTree(modifiedExtBidPrebid));

return bid.toBuilder().ext(updatedBidExt).build();
return updatedBidExt;
}

private ExtPrebid<ExtBidPrebid, ObjectNode> getExtPrebid(ObjectNode bidExt, String bidId) {
Expand All @@ -1681,31 +1728,30 @@ private ExtPrebid<ExtBidPrebid, ObjectNode> getExtPrebid(ObjectNode bidExt, Stri
}
}

private Bid updateBid(RubiconBid bid, Imp imp, Float cpmOverrideFromRequest, RubiconBidResponse bidResponse) {
String bidId = bid.getId();
if (generateBidId) {
// Since Rubicon XAPI returns openrtb_response.seatbid.bid.id not unique enough
// generate new value for it
bidId = UUID.randomUUID().toString();
} else if (Objects.equals(bid.getId(), "0")) {
// Since Rubicon XAPI returns only one bid per response
// copy bidResponse.bidid to openrtb_response.seatbid.bid.id
bidId = bidResponse.getBidid();
}
private static Integer resolveNetworkId(RubiconSeatBid seatBid) {
final String buyer = seatBid.getBuyer();
final int networkId = NumberUtils.toInt(buyer, 0);
return networkId <= 0 ? null : networkId;
}

// Unconditionally set price if coming from CPM override
final Float cpmOverride = ObjectUtils.defaultIfNull(cpmOverrideFromImp(imp), cpmOverrideFromRequest);
final BigDecimal bidPrice = cpmOverride != null
? new BigDecimal(String.valueOf(cpmOverride))
: bid.getPrice();
private String resolveRendererUrl(Imp imp, ExtBidPrebidMeta meta, BidType bidType, boolean hasApexRenderer) {
if (imp == null) {
return null;
}

final RubiconBid updatedRubiconBid = bid.toBuilder()
.id(bidId)
.adm(resolveAdm(bid.getAdm(), bid.getAdmNative()))
.price(bidPrice)
.build();
final Video video = imp.getVideo();
return hasApexRenderer
&& (bidType == BidType.video || isVideoMetaMediaType(meta))
&& (video != null && !Objects.equals(video.getPlacement(), 1) && !Objects.equals(video.getPlcmt(), 1))
? VIDEO_OUTSTREAM_APEX_META_RENDERER_URL
: null;
}

return bidFromRubiconBid(updatedRubiconBid);
private static Boolean isVideoMetaMediaType(ExtBidPrebidMeta meta) {
return Optional.ofNullable(meta)
.map(ExtBidPrebidMeta::getMediaType)
.map("video"::equalsIgnoreCase)
.orElse(false);
}

private String resolveAdm(String bidAdm, ObjectNode admobject) {
Expand All @@ -1725,7 +1771,6 @@ private Bid bidFromRubiconBid(RubiconBid rubiconBid) {
}

private static BidderBid createBidderBid(Bid bid, Imp imp, BidType bidType, String currency) {

return BidderBid.builder()
.bid(bid)
.type(bidType)
Expand All @@ -1734,8 +1779,7 @@ private static BidderBid createBidderBid(Bid bid, Imp imp, BidType bidType, Stri
.build();
}

private Float cpmOverrideFromRequest(BidRequest bidRequest) {
final RubiconExtPrebidBiddersBidder bidder = extPrebidBiddersRubicon(bidRequest.getExt());
private static Float cpmOverrideFromRequest(RubiconExtPrebidBiddersBidder bidder) {
final RubiconExtPrebidBiddersBidderDebug debug = bidder != null ? bidder.getDebug() : null;
return debug != null ? debug.getCpmoverride() : null;
}
Expand All @@ -1748,6 +1792,10 @@ private Float cpmOverrideFromImp(Imp imp) {
.orElse(null);
}

private static boolean hasApexRenderer(RubiconExtPrebidBiddersBidder bidder) {
return Optional.ofNullable(bidder).map(RubiconExtPrebidBiddersBidder::getApexRenderer).orElse(false);
}

private static BidType bidType(BidRequest bidRequest) {
final ImpMediaType impMediaType = impType(bidRequest.getImp().getFirst());
return switch (impMediaType) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.bidder.rubicon.proto.request;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;

Expand All @@ -10,4 +11,7 @@ public class RubiconExtPrebidBiddersBidder {
String integration;

RubiconExtPrebidBiddersBidderDebug debug;

@JsonProperty("apexRenderer")
Boolean apexRenderer;
}
Loading
Loading