22
33import com .fasterxml .jackson .core .type .TypeReference ;
44import com .fasterxml .jackson .databind .JsonNode ;
5- import com .fasterxml .jackson .databind .node .JsonNodeFactory ;
65import com .fasterxml .jackson .databind .node .ObjectNode ;
6+ import com .iab .openrtb .request .App ;
77import com .iab .openrtb .request .BidRequest ;
88import com .iab .openrtb .request .Imp ;
9+ import com .iab .openrtb .request .Site ;
910import com .iab .openrtb .request .Source ;
1011import com .iab .openrtb .response .Bid ;
1112import com .iab .openrtb .response .BidResponse ;
1213import com .iab .openrtb .response .SeatBid ;
1314import org .apache .commons .collections4 .CollectionUtils ;
15+ import org .apache .commons .lang3 .ObjectUtils ;
16+ import org .apache .commons .lang3 .StringUtils ;
1417import org .prebid .server .bidder .Bidder ;
1518import org .prebid .server .bidder .model .BidderBid ;
1619import org .prebid .server .bidder .model .BidderCall ;
4346public class ShowheroesBidder implements Bidder <BidRequest > {
4447
4548 private static final String BID_CURRENCY = "EUR" ;
46- private static final String DEFAULT_ORTB_CURRENCY = "USD" ;
4749 private static final String PBSP_JAVA = "java" ;
4850 private static final TypeReference <ExtPrebid <?, ExtImpShowheroes >> SHOWHEROES_EXT_TYPE_REFERENCE =
4951 new TypeReference <>() {
@@ -55,9 +57,9 @@ public class ShowheroesBidder implements Bidder<BidRequest> {
5557 private final String pbsVersion ;
5658
5759 public ShowheroesBidder (String endpointUrl ,
58- CurrencyConversionService currencyConversionService ,
59- PrebidVersionProvider prebidVersionProvider ,
60- JacksonMapper mapper ) {
60+ CurrencyConversionService currencyConversionService ,
61+ PrebidVersionProvider prebidVersionProvider ,
62+ JacksonMapper mapper ) {
6163
6264 this .endpointUrl = HttpUtil .validateUrl (Objects .requireNonNull (endpointUrl ));
6365 this .currencyConversionService = Objects .requireNonNull (currencyConversionService );
@@ -66,151 +68,123 @@ public ShowheroesBidder(String endpointUrl,
6668 this .pbsVersion = prebidVersionProvider .getNameVersionRecord ();
6769 }
6870
69- private BidderError validate (BidRequest bidRequest ) {
70- // request must contain site object with page or app object with bundle
71- if (bidRequest .getSite () == null && bidRequest .getApp () == null ) {
71+ @ Override
72+ public Result <List <HttpRequest <BidRequest >>> makeHttpRequests (BidRequest request ) {
73+ final BidderError validationError = validate (request .getSite (), request .getApp ());
74+ if (validationError != null ) {
75+ return Result .withError (validationError );
76+ }
77+
78+ final List <BidderError > errors = new ArrayList <>();
79+
80+ final ExtRequestPrebidChannel prebidChannel = getPrebidChannel (request );
81+ final List <Imp > modifiedImps = new ArrayList <>(request .getImp ().size ());
82+
83+ for (Imp impression : request .getImp ()) {
84+ try {
85+ modifiedImps .add (modifyImp (request , impression , prebidChannel ));
86+ } catch (Exception e ) {
87+ errors .add (BidderError .badInput (e .getMessage ()));
88+ }
89+ }
90+
91+ if (modifiedImps .isEmpty ()) {
92+ return Result .withErrors (errors );
93+ }
94+
95+ final Source source = modifySource (request );
96+ final BidRequest modifiedRequest = request .toBuilder ().imp (modifiedImps ).source (source ).build ();
97+ final HttpRequest <BidRequest > httpRequest = BidderUtil .defaultRequest (modifiedRequest , endpointUrl , mapper );
98+
99+ return Result .of (Collections .singletonList (httpRequest ), errors );
100+ }
101+
102+ private static BidderError validate (Site site , App app ) {
103+ if (site == null && app == null ) {
72104 return BidderError .badInput ("BidRequest must contain one of site or app" );
73105 }
74- if (bidRequest . getSite () != null && bidRequest . getSite () .getPage () == null ) {
106+ if (site != null && site .getPage () == null ) {
75107 return BidderError .badInput ("BidRequest.site.page is required" );
76108 }
77- if (bidRequest . getApp () != null && bidRequest . getApp () .getBundle () == null ) {
109+ if (app != null && app .getBundle () == null ) {
78110 return BidderError .badInput ("BidRequest.app.bundle is required" );
79111 }
80112 return null ;
81113 }
82114
83- private ExtRequestPrebidChannel getPrebidChannel (BidRequest bidRequest ) {
115+ private static ExtRequestPrebidChannel getPrebidChannel (BidRequest bidRequest ) {
84116 return Optional .ofNullable (bidRequest .getExt ())
85117 .map (ExtRequest ::getPrebid )
86118 .map (ExtRequestPrebid ::getChannel )
87119 .orElse (null );
88120 }
89121
90- private Imp processImpression (BidRequest bidRequest , Imp imp , ExtRequestPrebidChannel prebidChannel ) {
91- if (imp .getBanner () == null && imp .getVideo () == null ) {
92- throw new PreBidException ("Impression must contain one of banner or video" );
93- }
94-
95- final ExtImpShowheroes extImpShowheroes = mapper .mapper ()
96- .convertValue (imp .getExt (), SHOWHEROES_EXT_TYPE_REFERENCE ).getBidder ();
97- if (extImpShowheroes == null || extImpShowheroes .getUnitId () == null
98- || extImpShowheroes .getUnitId ().isBlank ()) {
99- throw new PreBidException ("unitId is required" );
100- }
101-
102- String channelName = null ;
103- String channelVersion = null ;
104- if (prebidChannel != null ) {
105- channelName = prebidChannel .getName ();
106- channelVersion = prebidChannel .getVersion ();
107- }
108-
109- final ObjectNode impExt = imp .getExt ();
122+ private Imp modifyImp (BidRequest bidRequest , Imp imp , ExtRequestPrebidChannel prebidChannel ) {
123+ final ExtImpShowheroes extImpShowheroes = parseImpExt (imp );
110124
111125 final Imp .ImpBuilder impBuilder = imp .toBuilder ();
112126
113- // copy unitId from ext.bidder to ext.params
114- impExt .set ("params" , JsonNodeFactory .instance .objectNode ()
115- .put ("unitId" , extImpShowheroes .getUnitId ()));
116-
117- impBuilder .ext (impExt );
118- if (imp .getDisplaymanager () == null && channelName != null ) {
119- impBuilder .displaymanager (channelName );
120- impBuilder .displaymanagerver (channelVersion );
127+ if (prebidChannel != null && imp .getDisplaymanager () == null ) {
128+ impBuilder .displaymanager (prebidChannel .getName ());
129+ impBuilder .displaymanagerver (prebidChannel .getVersion ());
121130 }
122131
123- String currency = imp .getBidfloorcur ();
124- // if floor price is 0, or currency is EUR - no need to convert
125- if (imp .getBidfloor () == null || imp .getBidfloor ().compareTo (BigDecimal .ZERO ) == 0
126- || currency == BID_CURRENCY ) {
132+ impBuilder .ext (modifyImpExt (imp , extImpShowheroes ));
133+
134+ if (!shouldConvertFloor (imp )) {
127135 return impBuilder .build ();
128136 }
129- if (currency != null && !currency .isBlank ()) {
130- // if not provided default currency is USD
131- currency = DEFAULT_ORTB_CURRENCY ;
132- }
133137
134- final BigDecimal eurFloor = currencyConversionService .convertCurrency (
135- imp .getBidfloor (), bidRequest , currency , BID_CURRENCY );
136138 return impBuilder
137139 .bidfloorcur (BID_CURRENCY )
138- .bidfloor (eurFloor )
140+ .bidfloor (resolveBidFloor ( bidRequest , imp ) )
139141 .build ();
140142 }
141143
142- private Source getPBSSource (BidRequest bidRequest ) {
143- Source source = bidRequest .getSource ();
144- if (source == null ) {
145- source = Source .builder ().build ();
146- }
147-
148- ExtSource extSource = source .getExt ();
149- if (extSource == null ) {
150- extSource = ExtSource .of (null );
151- }
152-
153- JsonNode prebidExt = extSource .getProperty ("pbs" );
154- if (prebidExt == null || !prebidExt .isObject ()) {
155- prebidExt = mapper .mapper ().createObjectNode ();
144+ private ExtImpShowheroes parseImpExt (Imp imp ) {
145+ try {
146+ return mapper .mapper ().convertValue (imp .getExt (), SHOWHEROES_EXT_TYPE_REFERENCE ).getBidder ();
147+ } catch (IllegalArgumentException e ) {
148+ throw new PreBidException (e .getMessage ());
156149 }
157-
158- ((ObjectNode ) prebidExt ).put ("pbsv" , pbsVersion ).put ("pbsp" , PBSP_JAVA );
159-
160- extSource .addProperty ("pbs" , prebidExt );
161-
162- return source .toBuilder ().ext (extSource ).build ();
163150 }
164151
165- @ Override
166- public Result <List <HttpRequest <BidRequest >>> makeHttpRequests (BidRequest request ) {
167- final BidderError validationError = validate (request );
168- if (validationError != null ) {
169- return Result .of (Collections .emptyList (), List .of (validationError ));
170- }
171-
172- final List <BidderError > errors = new ArrayList <>();
173- final List <HttpRequest <BidRequest >> httpRequests = new ArrayList <>();
152+ private ObjectNode modifyImpExt (Imp imp , ExtImpShowheroes shImpExt ) {
153+ final ObjectNode impExt = ObjectUtils .defaultIfNull (imp .getExt (), mapper .mapper ().createObjectNode ());
154+ impExt .set ("params" , mapper .mapper ().createObjectNode ().put ("unitId" , shImpExt .getUnitId ()));
155+ return impExt ;
156+ }
174157
175- final ExtRequestPrebidChannel prebidChannel = getPrebidChannel (request );
176- final List <Imp > modifiedImps = new ArrayList <>(request .getImp ().size ());
158+ private static boolean shouldConvertFloor (Imp imp ) {
159+ return BidderUtil .isValidPrice (imp .getBidfloor ())
160+ && !StringUtils .equalsIgnoreCase (imp .getBidfloorcur (), BID_CURRENCY );
161+ }
177162
178- for (Imp impression : request .getImp ()) {
179- try {
180- modifiedImps .add (processImpression (request , impression , prebidChannel ));
181- } catch (Exception e ) {
182- errors .add (BidderError .badInput (e .getMessage ()));
183- continue ;
184- }
185- }
163+ private BigDecimal resolveBidFloor (BidRequest bidRequest , Imp imp ) {
164+ return currencyConversionService .convertCurrency (
165+ imp .getBidfloor (), bidRequest , imp .getBidfloorcur (), BID_CURRENCY );
166+ }
186167
187- if (modifiedImps .isEmpty ()) {
188- return Result .of (httpRequests , errors );
168+ private Source modifySource (BidRequest bidRequest ) {
169+ if (pbsVersion == null ) {
170+ return bidRequest .getSource ();
189171 }
190- Source source = request . getSource ();
191- if ( pbsVersion != null ) {
192- source = getPBSSource ( request );
193- }
194-
195- httpRequests . add ( makeHttpRequest ( request . toBuilder (). imp ( modifiedImps ). source ( source ). build ()));
196- return Result . of ( httpRequests , errors );
197- }
172+ final Source source = ObjectUtils . defaultIfNull ( bidRequest . getSource (), Source . builder (). build () );
173+ final ExtSource extSource = ObjectUtils . defaultIfNull ( source . getExt (), ExtSource . of ( null ));
174+ final ObjectNode prebidExtSource = Optional . ofNullable ( extSource . getProperty ( "pbs" ))
175+ . filter ( JsonNode :: isObject )
176+ . map ( ObjectNode . class :: cast )
177+ . orElseGet (() -> mapper . mapper (). createObjectNode ())
178+ . put ( "pbsv" , pbsVersion )
179+ . put ( "pbsp" , PBSP_JAVA );
198180
199- private HttpRequest < BidRequest > makeHttpRequest ( BidRequest request ) {
200- return BidderUtil . defaultRequest ( request , endpointUrl , mapper );
181+ extSource . addProperty ( "pbs" , prebidExtSource );
182+ return source . toBuilder (). ext ( extSource ). build ( );
201183 }
202184
203185 @ Override
204186 public Result <List <BidderBid >> makeBids (BidderCall <BidRequest > httpCall , BidRequest bidRequest ) {
205187 final BidResponse bidResponse ;
206- final int statusCode = httpCall .getResponse ().getStatusCode ();
207- if (statusCode == 204 ) {
208- return Result .of (Collections .emptyList (), Collections .emptyList ());
209- }
210- if (statusCode != 200 ) {
211- return Result .withError (BidderError .badServerResponse (
212- "Unexpected status code: " + statusCode ));
213- }
214188
215189 try {
216190 bidResponse = mapper .decodeValue (httpCall .getResponse ().getBody (), BidResponse .class );
@@ -241,7 +215,7 @@ private BidType getBidType(Bid bid) {
241215 return switch (bid .getMtype ()) {
242216 case 1 -> BidType .banner ;
243217 case 2 -> BidType .video ;
244- case null , default -> BidType .video ; // if not provided video is assumed
218+ case null , default -> BidType .video ;
245219 };
246220 }
247221}
0 commit comments