1010import com .iab .openrtb .response .Bid ;
1111import com .iab .openrtb .response .BidResponse ;
1212import com .iab .openrtb .response .SeatBid ;
13- import io .vertx .core .http .HttpMethod ;
1413import org .apache .commons .collections4 .CollectionUtils ;
1514import org .prebid .server .bidder .Bidder ;
1615import org .prebid .server .bidder .model .BidderBid ;
2120import org .prebid .server .json .DecodeException ;
2221import org .prebid .server .json .JacksonMapper ;
2322import org .prebid .server .proto .openrtb .ext .request .ExtPublisher ;
23+ import org .prebid .server .proto .openrtb .ext .request .sparteo .ExtImpSparteo ;
2424import org .prebid .server .proto .openrtb .ext .response .BidType ;
2525import org .prebid .server .proto .openrtb .ext .response .ExtBidPrebid ;
2626import org .prebid .server .util .BidderUtil ;
2727import org .prebid .server .util .HttpUtil ;
2828
2929import java .util .ArrayList ;
30+ import java .util .Collection ;
3031import java .util .Collections ;
31- import java .util .Iterator ;
3232import java .util .List ;
3333import java .util .Objects ;
3434
@@ -42,89 +42,158 @@ public SparteoBidder(String endpointUrl, JacksonMapper mapper) {
4242 this .mapper = Objects .requireNonNull (mapper );
4343 }
4444
45- private static <T > Iterable <T > iterable (Iterator <T > it ) {
46- return () -> it ;
47- }
48-
4945 @ Override
5046 public Result <List <HttpRequest <BidRequest >>> makeHttpRequests (BidRequest request ) {
5147 final List <BidderError > errors = new ArrayList <>();
52-
53- String siteNetworkId = null ;
5448 final List <Imp > modifiedImps = new ArrayList <>();
49+ String siteNetworkId = null ;
5550
5651 for (Imp imp : request .getImp ()) {
5752 try {
58- final ObjectNode extMap = mapper .mapper ()
59- .convertValue (imp .getExt (), ObjectNode .class );
60-
61- final ObjectNode bidderNode = (ObjectNode ) extMap .remove ("bidder" );
53+ final JsonNode bidderNode = imp .getExt ().get ("bidder" );
54+ final ExtImpSparteo bidderParams = mapper .mapper ().treeToValue (bidderNode , ExtImpSparteo .class );
6255
63- if (bidderNode != null ) {
64- if (siteNetworkId == null && bidderNode .hasNonNull ("networkId" )) {
65- siteNetworkId = bidderNode .get ("networkId" ).asText ();
66- }
67-
68- final ObjectNode sparteoNode = extMap .has ("sparteo" ) && extMap .get ("sparteo" ).isObject ()
69- ? (ObjectNode ) extMap .get ("sparteo" )
70- : extMap .putObject ("sparteo" );
71- final ObjectNode paramsNode = sparteoNode .has ("params" ) && sparteoNode .get ("params" ).isObject ()
72- ? (ObjectNode ) sparteoNode .get ("params" )
73- : sparteoNode .putObject ("params" );
74-
75- for (String field : iterable (bidderNode .fieldNames ())) {
76- paramsNode .set (field , bidderNode .get (field ));
77- }
56+ if (siteNetworkId == null && bidderParams .getNetworkId () != null ) {
57+ siteNetworkId = bidderParams .getNetworkId ();
7858 }
7959
80- modifiedImps .add (imp .toBuilder ().ext (extMap ).build ());
81- } catch (Exception e ) {
60+ final ObjectNode modifiedExt = buildImpExt (imp , bidderParams , mapper );
61+
62+ modifiedImps .add (imp .toBuilder ().ext (modifiedExt ).build ());
63+ } catch (NullPointerException | JsonProcessingException e ) {
8264 errors .add (BidderError .badInput (
8365 String .format ("ignoring imp id=%s, error processing ext: %s" ,
84- imp .getId (), e .getMessage ())));
66+ imp .getId (), e .getMessage ())));
8567 }
8668 }
8769
8870 if (modifiedImps .isEmpty ()) {
8971 return Result .withErrors (errors );
9072 }
9173
92- final BidRequest .BidRequestBuilder rb = request .toBuilder ().imp (modifiedImps );
74+ final BidRequest outgoingRequest = request .toBuilder ()
75+ .imp (modifiedImps )
76+ .site (modifySite (request .getSite (), siteNetworkId , mapper ))
77+ .build ();
78+
79+ final HttpRequest <BidRequest > call = BidderUtil .defaultRequest (outgoingRequest , endpointUrl , mapper );
80+
81+ return Result .of (Collections .singletonList (call ), errors );
82+ }
83+
84+ @ Override
85+ public Result <List <BidderBid >> makeBids (BidderCall <BidRequest > httpCall , BidRequest bidRequest ) {
86+ final List <BidderError > errors = new ArrayList <>();
87+ final int statusCode = httpCall .getResponse ().getStatusCode ();
9388
94- final Site site = request .getSite ();
95- if (site != null && site .getPublisher () != null && siteNetworkId != null ) {
96- final Publisher pub = site .getPublisher ();
89+ if (statusCode == 204 ) {
90+ return Result .of (Collections .emptyList (), errors );
91+ }
92+
93+ if (statusCode != 200 ) {
94+ return Result .withError (BidderError .badServerResponse (
95+ String .format ("HTTP status %d returned from Sparteo" , statusCode )));
96+ }
97+
98+ try {
99+ final BidResponse bidResponse = mapper .decodeValue (httpCall .getResponse ().getBody (), BidResponse .class );
100+ return Result .of (extractBids (bidResponse , errors ), errors );
101+ } catch (DecodeException e ) {
102+ return Result .withError (BidderError .badServerResponse (
103+ String .format ("Failed to decode Sparteo response: %s" , e .getMessage ())));
104+ }
105+ }
106+
107+ private ObjectNode buildImpExt (Imp imp , ExtImpSparteo bidderParams , JacksonMapper mapper )
108+ throws JsonProcessingException {
109+
110+ final ObjectNode extMap = mapper .mapper ().convertValue (imp .getExt (), ObjectNode .class );
111+
112+ extMap .remove ("bidder" );
113+
114+ final JsonNode sparteoNode = extMap .get ("sparteo" );
115+ final ObjectNode outgoingParamsNode ;
116+
117+ if (sparteoNode != null && sparteoNode .isObject () && sparteoNode .has ("params" )
118+ && sparteoNode .get ("params" ).isObject ()) {
119+ outgoingParamsNode = (ObjectNode ) sparteoNode .get ("params" );
120+ } else {
121+ outgoingParamsNode = extMap .putObject ("sparteo" ).putObject ("params" );
122+ }
123+
124+ final ObjectNode bidderParamsAsNode = mapper .mapper ().convertValue (bidderParams , ObjectNode .class );
125+ outgoingParamsNode .setAll (bidderParamsAsNode );
126+
127+ final JsonNode prebidNode = extMap .get ("prebid" );
128+ if (prebidNode != null && prebidNode .has ("adunitcode" )) {
129+ outgoingParamsNode .set ("adUnitCode" , prebidNode .get ("adunitcode" ));
130+ }
131+
132+ return extMap ;
133+ }
134+
135+ private Site modifySite (Site site , String siteNetworkId , JacksonMapper mapper ) {
136+ if (site == null || site .getPublisher () == null || siteNetworkId == null ) {
137+ return site ;
138+ }
97139
98- final ObjectNode pubExtRaw = pub .getExt () != null
99- ? mapper .mapper ().convertValue (pub .getExt (), ObjectNode .class )
100- : mapper .mapper ().createObjectNode ();
140+ final Publisher publisher = site .getPublisher ();
141+ final ExtPublisher extPublisher ;
101142
102- pubExtRaw .withObjectProperty ("params" ).put ("networkId" , siteNetworkId );
143+ extPublisher = publisher .getExt () != null
144+ ? publisher .getExt ()
145+ : ExtPublisher .empty ();
103146
104- final ExtPublisher extPub = mapper . mapper ()
105- . convertValue ( pubExtRaw , ExtPublisher . class ) ;
147+ final JsonNode paramsProperty = extPublisher . getProperty ( "params" );
148+ final ObjectNode paramsNode ;
106149
107- final Publisher newPub = pub .toBuilder ().ext (extPub ).build ();
108- final Site newSite = site .toBuilder ().publisher (newPub ).build ();
109- rb .site (newSite );
150+ if (paramsProperty != null && paramsProperty .isObject ()) {
151+ paramsNode = (ObjectNode ) paramsProperty ;
152+ } else {
153+ paramsNode = mapper .mapper ().createObjectNode ();
154+ extPublisher .addProperty ("params" , paramsNode );
110155 }
111156
112- final BidRequest outgoing = rb . build ( );
157+ paramsNode . put ( "networkId" , siteNetworkId );
113158
114- final HttpRequest <BidRequest > call = HttpRequest .<BidRequest >builder ()
115- .method (HttpMethod .POST )
116- .uri (endpointUrl )
117- .headers (HttpUtil .headers ())
118- .impIds (BidderUtil .impIds (outgoing ))
119- .body (mapper .encodeToBytes (outgoing ))
120- .payload (outgoing )
159+ final Publisher modifiedPublisher = publisher .toBuilder ()
160+ .ext (extPublisher )
121161 .build ();
122162
123- final List <HttpRequest <BidRequest >> calls = Collections .singletonList (call );
163+ return site .toBuilder ()
164+ .publisher (modifiedPublisher )
165+ .build ();
166+ }
167+
168+ private List <BidderBid > extractBids (BidResponse bidResponse , List <BidderError > errors ) {
169+ if (bidResponse == null || CollectionUtils .isEmpty (bidResponse .getSeatbid ())) {
170+ return Collections .emptyList ();
171+ }
124172
125- return errors .isEmpty ()
126- ? Result .withValues (calls )
127- : Result .of (calls , errors );
173+ return bidResponse .getSeatbid ().stream ()
174+ .filter (Objects ::nonNull )
175+ .map (SeatBid ::getBid )
176+ .filter (Objects ::nonNull )
177+ .flatMap (Collection ::stream )
178+ .map (bid -> {
179+ if (bid == null ) {
180+ errors .add (BidderError .badServerResponse ("Received null bid object within a seatbid." ));
181+ return null ;
182+ }
183+ return toBidderBid (bid , bidResponse .getCur (), errors );
184+ })
185+ .filter (Objects ::nonNull )
186+ .toList ();
187+ }
188+
189+ private BidderBid toBidderBid (Bid bid , String currency , List <BidderError > errors ) {
190+ try {
191+ final BidType bidType = getBidTypeFromBidExtension (bid );
192+ return BidderBid .of (bid , bidType , currency );
193+ } catch (Exception e ) {
194+ errors .add (BidderError .badServerResponse (e .getMessage ()));
195+ return null ;
196+ }
128197 }
129198
130199 private BidType getBidTypeFromBidExtension (Bid bid ) throws Exception {
@@ -168,58 +237,4 @@ private BidType getBidTypeFromBidExtension(Bid bid) throws Exception {
168237
169238 return bidType ;
170239 }
171-
172- @ Override
173- public Result <List <BidderBid >> makeBids (BidderCall <BidRequest > httpCall , BidRequest bidRequest ) {
174- final List <BidderError > errors = new ArrayList <>();
175-
176- final int status = httpCall .getResponse ().getStatusCode ();
177- if (status == 204 ) {
178- return Result .of (Collections .emptyList (), errors );
179- }
180- if (status != 200 ) {
181- errors .add (BidderError .badServerResponse (
182- String .format ("HTTP status %d returned from Sparteo" , status ))
183- );
184- return Result .of (Collections .emptyList (), errors );
185- }
186-
187- final BidResponse bidResponse ;
188- try {
189- bidResponse = mapper .decodeValue (httpCall .getResponse ().getBody (), BidResponse .class );
190- } catch (DecodeException e ) {
191- errors .add (BidderError .badServerResponse (
192- String .format ("Failed to decode Sparteo response: %s" , e .getMessage ()))
193- );
194- return Result .of (Collections .emptyList (), errors );
195- }
196-
197- if (bidResponse == null || CollectionUtils .isEmpty (bidResponse .getSeatbid ())) {
198- return Result .of (Collections .emptyList (), errors );
199- }
200-
201- final List <BidderBid > bidderBids = new ArrayList <>();
202- final String currency = bidResponse .getCur ();
203-
204- for (SeatBid seatBid : bidResponse .getSeatbid ()) {
205- if (seatBid != null && CollectionUtils .isNotEmpty (seatBid .getBid ())) {
206- for (Bid bid : seatBid .getBid ()) {
207- if (bid == null ) {
208- errors .add (BidderError .badServerResponse (
209- "Received null bid object within a seatbid." )
210- );
211- continue ;
212- }
213- try {
214- final BidType type = getBidTypeFromBidExtension (bid );
215- bidderBids .add (BidderBid .of (bid , type , currency ));
216- } catch (Exception e ) {
217- errors .add (BidderError .badServerResponse (e .getMessage ()));
218- }
219- }
220- }
221- }
222-
223- return Result .of (bidderBids , errors );
224- }
225240}
0 commit comments