44import com .fasterxml .jackson .core .type .TypeReference ;
55import com .fasterxml .jackson .databind .JsonNode ;
66import com .fasterxml .jackson .databind .node .ObjectNode ;
7+ import com .iab .openrtb .request .App ;
78import com .iab .openrtb .request .BidRequest ;
89import com .iab .openrtb .request .Imp ;
910import com .iab .openrtb .request .Publisher ;
@@ -40,6 +41,8 @@ public class SparteoBidder implements Bidder<BidRequest> {
4041
4142 private static final String NETWORK_ID_MACRO = "{{NetworkId}}" ;
4243 private static final String DOMAIN_MACRO = "{{Domain}}" ;
44+ private static final String BUNDLE_QUERY_MACRO = "{{BundleQuery}}" ;
45+
4346 private static final TypeReference <ExtPrebid <?, ExtImpSparteo >> TYPE_REFERENCE =
4447 new TypeReference <>() { };
4548
@@ -55,19 +58,18 @@ public SparteoBidder(String endpointUrl, JacksonMapper mapper) {
5558 public Result <List <HttpRequest <BidRequest >>> makeHttpRequests (BidRequest request ) {
5659 final List <BidderError > errors = new ArrayList <>();
5760 final List <Imp > modifiedImps = new ArrayList <>();
58- String siteNetworkId = null ;
61+ String networkId = null ;
5962
6063 for (Imp imp : request .getImp ()) {
61- if (siteNetworkId == null ) {
64+ if (networkId == null ) {
6265 try {
63- siteNetworkId = parseExtImp (imp ).getNetworkId ();
66+ networkId = parseExtImp (imp ).getNetworkId ();
6467 } catch (PreBidException e ) {
6568 errors .add (BidderError .badInput (
6669 "ignoring imp id=%s, error processing ext: %s" .formatted (
6770 imp .getId (), e .getMessage ())));
6871 }
6972 }
70-
7173 final ObjectNode modifiedExt = modifyImpExt (imp );
7274 modifiedImps .add (imp .toBuilder ().ext (modifiedExt ).build ());
7375 }
@@ -76,12 +78,22 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request
7678 return Result .withErrors (errors );
7779 }
7880
79- final BidRequest outgoingRequest = request .toBuilder ()
80- .imp (modifiedImps )
81- .site (modifySite (request .getSite (), siteNetworkId , mapper ))
82- .build ();
81+ final BidRequest .BidRequestBuilder builder = request .toBuilder ().imp (modifiedImps );
82+
83+ final Site site = request .getSite ();
84+ final App app = request .getApp ();
85+
86+ if (networkId != null ) {
87+ if (site != null ) {
88+ builder .site (modifySite (site , networkId , mapper ));
89+ } else if (app != null ) {
90+ builder .app (modifyApp (app , networkId , mapper ));
91+ }
92+ }
93+
94+ final BidRequest outgoingRequest = builder .build ();
8395
84- final String finalEndpointUrl = replaceMacros (request . getSite (), siteNetworkId );
96+ final String finalEndpointUrl = replaceMacros (site , app , networkId );
8597 final HttpRequest <BidRequest > call = BidderUtil .defaultRequest (outgoingRequest , finalEndpointUrl , mapper );
8698
8799 return Result .of (Collections .singletonList (call ), errors );
@@ -99,19 +111,22 @@ private ObjectNode modifyImpExt(Imp imp) {
99111 final ObjectNode modifiedImpExt = imp .getExt ().deepCopy ();
100112 final ObjectNode sparteoNode = modifiedImpExt .putObject ("sparteo" );
101113 final JsonNode bidderJsonNode = modifiedImpExt .remove ("bidder" );
114+ // if bidder is null, 'params' will become null (allowed); endpoint logic relies on networkId collected above
102115 sparteoNode .set ("params" , bidderJsonNode );
103-
104116 return modifiedImpExt ;
105117 }
106118
107- private Site modifySite (Site site , String siteNetworkId , JacksonMapper mapper ) {
108- if (site == null || site .getPublisher () == null || siteNetworkId == null ) {
119+ // -- Defensive upsert into site.publisher.ext.params.networkId
120+ private Site modifySite (Site site , String networkId , JacksonMapper mapper ) {
121+ if (site == null || networkId == null ) {
109122 return site ;
110123 }
111124
112- final Publisher originalPublisher = site .getPublisher ();
113- final ExtPublisher originalExt = originalPublisher .getExt ();
125+ final Publisher originalPublisher = site .getPublisher () != null
126+ ? site .getPublisher ()
127+ : Publisher .builder ().build ();
114128
129+ final ExtPublisher originalExt = originalPublisher .getExt ();
115130 final ExtPublisher modifiedExt = originalExt != null
116131 ? ExtPublisher .of (originalExt .getPrebid ())
117132 : ExtPublisher .empty ();
@@ -120,47 +135,94 @@ private Site modifySite(Site site, String siteNetworkId, JacksonMapper mapper) {
120135 mapper .fillExtension (modifiedExt , originalExt );
121136 }
122137
123- final JsonNode paramsProperty = modifiedExt . getProperty ( "params" );
124- final ObjectNode paramsNode ;
138+ final ObjectNode paramsNode = ensureParamsNode ( modifiedExt );
139+ paramsNode . put ( "networkId" , networkId ) ;
125140
126- if (paramsProperty != null && paramsProperty .isObject ()) {
127- paramsNode = (ObjectNode ) paramsProperty ;
128- } else {
129- paramsNode = mapper .mapper ().createObjectNode ();
130- modifiedExt .addProperty ("params" , paramsNode );
141+ final Publisher modifiedPublisher = originalPublisher .toBuilder ()
142+ .ext (modifiedExt )
143+ .build ();
144+
145+ return site .toBuilder ().publisher (modifiedPublisher ).build ();
146+ }
147+
148+ // -- Defensive upsert into app.publisher.ext.params.networkId
149+ private App modifyApp (App app , String networkId , JacksonMapper mapper ) {
150+ if (app == null || networkId == null ) {
151+ return app ;
152+ }
153+
154+ final Publisher originalPublisher = app .getPublisher () != null
155+ ? app .getPublisher ()
156+ : Publisher .builder ().build ();
157+
158+ final ExtPublisher originalExt = originalPublisher .getExt ();
159+ final ExtPublisher modifiedExt = originalExt != null
160+ ? ExtPublisher .of (originalExt .getPrebid ())
161+ : ExtPublisher .empty ();
162+
163+ if (originalExt != null ) {
164+ mapper .fillExtension (modifiedExt , originalExt );
131165 }
132166
133- paramsNode .put ("networkId" , siteNetworkId );
167+ final ObjectNode paramsNode = ensureParamsNode (modifiedExt );
168+ paramsNode .put ("networkId" , networkId );
134169
135170 final Publisher modifiedPublisher = originalPublisher .toBuilder ()
136171 .ext (modifiedExt )
137172 .build ();
138173
139- return site .toBuilder ()
140- .publisher (modifiedPublisher )
141- .build ();
174+ return app .toBuilder ().publisher (modifiedPublisher ).build ();
142175 }
143176
144- private String replaceMacros (Site site , String siteNetworkId ) {
145- final String domain = Optional .ofNullable (site )
146- .map (s -> Optional .ofNullable (s .getPublisher ()).map (Publisher ::getDomain ).orElse (s .getDomain ()))
147- .orElse (null );
177+ private ObjectNode ensureParamsNode (ExtPublisher extPublisher ) {
178+ final JsonNode paramsProperty = extPublisher .getProperty ("params" );
179+ if (paramsProperty != null && paramsProperty .isObject ()) {
180+ return (ObjectNode ) paramsProperty ;
181+ }
182+ final ObjectNode paramsNode = mapper .mapper ().createObjectNode ();
183+ extPublisher .addProperty ("params" , paramsNode );
184+ return paramsNode ;
185+ }
148186
149- return resolveEndpoint (domain , siteNetworkId );
187+ private String replaceMacros (Site site , App app , String networkId ) {
188+ final String domain = resolveDomain (site , app );
189+ final String bundle = Optional .ofNullable (app ).map (App ::getBundle ).orElse (null );
190+ return resolveEndpoint (domain , networkId , bundle );
150191 }
151192
152- private String resolveEndpoint (String domain , String networkId ) {
153- if (networkId == null ) {
154- return endpointUrl ;
193+ private String resolveDomain (Site site , App app ) {
194+ if (site != null ) {
195+ final String siteDomain = site .getDomain ();
196+ if (siteDomain != null && !siteDomain .isEmpty ()) {
197+ return siteDomain ;
198+ }
199+ final Publisher pub = site .getPublisher ();
200+ if (pub != null && pub .getDomain () != null && !pub .getDomain ().isEmpty ()) {
201+ return pub .getDomain ();
202+ }
155203 }
204+ if (app != null && app .getDomain () != null && !app .getDomain ().isEmpty ()) {
205+ return app .getDomain ();
206+ }
207+ return null ;
208+ }
156209
157- final String uri = endpointUrl .replace (NETWORK_ID_MACRO , HttpUtil .encodeUrl (networkId ));
210+ private String resolveEndpoint (String domain , String networkId , String bundle ) {
211+ String uri = endpointUrl ;
158212
159- if (domain == null ) {
160- return uri ;
213+ if (networkId != null && ! networkId . isEmpty () ) {
214+ uri = uri . replace ( NETWORK_ID_MACRO , HttpUtil . encodeUrl ( networkId )) ;
161215 }
216+ if (domain != null && !domain .isEmpty ()) {
217+ uri = uri .replace (DOMAIN_MACRO , HttpUtil .encodeUrl (domain ));
218+ }
219+
220+ final String bundleQuery = (bundle != null && !bundle .isEmpty ())
221+ ? "&bundle=" + HttpUtil .encodeUrl (bundle )
222+ : "" ;
223+ uri = uri .replace (BUNDLE_QUERY_MACRO , bundleQuery );
162224
163- return uri . replace ( DOMAIN_MACRO , HttpUtil . encodeUrl ( domain )) ;
225+ return uri ;
164226 }
165227
166228 @ Override
0 commit comments