@@ -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 ) {
0 commit comments