Skip to content

Commit 8609e25

Browse files
Core: Support Bidder Specific Imp Level Params (#3254)
1 parent ef313c0 commit 8609e25

23 files changed

Lines changed: 4270 additions & 2909 deletions

File tree

src/main/java/org/prebid/server/auction/ExchangeService.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,6 @@
150150
import java.util.stream.Collectors;
151151
import java.util.stream.Stream;
152152

153-
/**
154-
* Executes an OpenRTB v2.5-2.6 Auction.
155-
*/
156153
public class ExchangeService {
157154

158155
private static final Logger logger = LoggerFactory.getLogger(ExchangeService.class);
@@ -174,6 +171,7 @@ public class ExchangeService {
174171
private final StoredResponseProcessor storedResponseProcessor;
175172
private final PrivacyEnforcementService privacyEnforcementService;
176173
private final FpdResolver fpdResolver;
174+
private final ImpAdjuster impAdjuster;
177175
private final SupplyChainResolver supplyChainResolver;
178176
private final DebugResolver debugResolver;
179177
private final MediaTypeProcessor mediaTypeProcessor;
@@ -204,6 +202,7 @@ public ExchangeService(double logSamplingRate,
204202
StoredResponseProcessor storedResponseProcessor,
205203
PrivacyEnforcementService privacyEnforcementService,
206204
FpdResolver fpdResolver,
205+
ImpAdjuster impAdjuster,
207206
SupplyChainResolver supplyChainResolver,
208207
DebugResolver debugResolver,
209208
MediaTypeProcessor mediaTypeProcessor,
@@ -234,6 +233,7 @@ public ExchangeService(double logSamplingRate,
234233
this.storedResponseProcessor = Objects.requireNonNull(storedResponseProcessor);
235234
this.privacyEnforcementService = Objects.requireNonNull(privacyEnforcementService);
236235
this.fpdResolver = Objects.requireNonNull(fpdResolver);
236+
this.impAdjuster = Objects.requireNonNull(impAdjuster);
237237
this.supplyChainResolver = Objects.requireNonNull(supplyChainResolver);
238238
this.debugResolver = Objects.requireNonNull(debugResolver);
239239
this.mediaTypeProcessor = Objects.requireNonNull(mediaTypeProcessor);
@@ -299,7 +299,6 @@ private Future<AuctionContext> runAuction(AuctionContext receivedContext) {
299299
.map(receivedContext::with))
300300

301301
.map(context -> updateRequestMetric(context, uidsCookie, aliases, account, requestTypeMetric))
302-
303302
.compose(context -> CompositeFuture.join(
304303
context.getAuctionParticipations().stream()
305304
.map(auctionParticipation -> processAndRequestBids(
@@ -528,7 +527,6 @@ private Future<List<AuctionParticipation>> extractAuctionParticipations(
528527
.toList();
529528
final Map<String, Map<String, String>> impBidderToStoredBidResponse =
530529
storedResponseResult.getImpBidderToStoredBidResponse();
531-
532530
return makeAuctionParticipation(
533531
bidders,
534532
context,
@@ -852,6 +850,7 @@ private AuctionParticipation createAuctionParticipation(
852850
bidderToMultiBid,
853851
biddersToConfigs,
854852
bidderToPrebidBidders,
853+
bidderAliases,
855854
context);
856855

857856
final BidderRequest bidderRequest = BidderRequest.builder()
@@ -878,6 +877,7 @@ private BidRequest prepareBidRequest(BidderPrivacyResult bidderPrivacyResult,
878877
Map<String, MultiBidConfig> bidderToMultiBid,
879878
Map<String, ExtBidderConfigOrtb> biddersToConfigs,
880879
Map<String, JsonNode> bidderToPrebidBidders,
880+
BidderAliases bidderAliases,
881881
AuctionContext context) {
882882

883883
final String bidder = bidderPrivacyResult.getRequestBidder();
@@ -938,6 +938,7 @@ private BidRequest prepareBidRequest(BidderPrivacyResult bidderPrivacyResult,
938938
transmitTid,
939939
useFirstPartyData,
940940
context.getAccount(),
941+
bidderAliases,
941942
context.getDebugWarnings());
942943

943944
return bidRequest.toBuilder()
@@ -975,10 +976,12 @@ private List<Imp> prepareImps(String bidder,
975976
boolean transmitTid,
976977
boolean useFirstPartyData,
977978
Account account,
979+
BidderAliases bidderAliases,
978980
List<String> debugWarnings) {
979981

980982
return bidRequest.getImp().stream()
981983
.filter(imp -> bidderParamsFromImpExt(imp.getExt()).hasNonNull(bidder))
984+
.map(imp -> impAdjuster.adjust(imp, bidder, bidderAliases, debugWarnings))
982985
.map(imp -> prepareImp(imp, bidder, bidRequest, transmitTid, useFirstPartyData, account, debugWarnings))
983986
.toList();
984987
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.prebid.server.auction;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.node.ObjectNode;
5+
import com.iab.openrtb.request.Imp;
6+
import org.prebid.server.json.JacksonMapper;
7+
import org.prebid.server.json.JsonMerger;
8+
import org.prebid.server.validation.ImpValidator;
9+
10+
import java.util.Iterator;
11+
import java.util.List;
12+
import java.util.Objects;
13+
import java.util.Optional;
14+
15+
public class ImpAdjuster {
16+
17+
private static final String IMP_EXT = "ext";
18+
private static final String EXT_PREBID = "prebid";
19+
private static final String EXT_PREBID_BIDDER = "bidder";
20+
private static final String EXT_PREBID_IMP = "imp";
21+
22+
private final ImpValidator impValidator;
23+
private final JacksonMapper jacksonMapper;
24+
private final JsonMerger jsonMerger;
25+
26+
public ImpAdjuster(JacksonMapper jacksonMapper,
27+
JsonMerger jsonMerger,
28+
ImpValidator impValidator) {
29+
30+
this.impValidator = Objects.requireNonNull(impValidator);
31+
this.jacksonMapper = Objects.requireNonNull(jacksonMapper);
32+
this.jsonMerger = Objects.requireNonNull(jsonMerger);
33+
}
34+
35+
public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, List<String> debugMessages) {
36+
final JsonNode impExtPrebidImp = bidderParamsFromImpExtPrebidImp(originalImp.getExt());
37+
if (impExtPrebidImp == null) {
38+
return originalImp;
39+
}
40+
41+
final JsonNode bidderNode = getBidderNode(bidder, bidderAliases, impExtPrebidImp);
42+
43+
if (bidderNode == null || bidderNode.isEmpty()) {
44+
return originalImp;
45+
}
46+
47+
// remove circular references according to the requirements
48+
removeExtPrebidBidder(bidderNode);
49+
50+
try {
51+
final JsonNode originalImpNode = jacksonMapper.mapper().valueToTree(originalImp);
52+
final JsonNode mergedImpNode = jsonMerger.merge(bidderNode, originalImpNode);
53+
54+
// clean up merged imp.ext.prebid.imp
55+
removeImpExtPrebidImp(mergedImpNode);
56+
57+
final Imp resultImp = jacksonMapper.mapper().convertValue(mergedImpNode, Imp.class);
58+
59+
impValidator.validateImp(resultImp);
60+
return resultImp;
61+
} catch (Exception e) {
62+
debugMessages.add("imp.ext.prebid.imp.%s can not be merged into original imp [id=%s], reason: %s"
63+
.formatted(bidder, originalImp.getId(), e.getMessage()));
64+
return originalImp;
65+
}
66+
}
67+
68+
private static JsonNode bidderParamsFromImpExtPrebidImp(ObjectNode ext) {
69+
return Optional.ofNullable(ext)
70+
.map(extNode -> extNode.get(EXT_PREBID))
71+
.map(prebidNode -> prebidNode.get(EXT_PREBID_IMP))
72+
.orElse(null);
73+
}
74+
75+
private static JsonNode getBidderNode(String bidderName, BidderAliases bidderAliases, JsonNode node) {
76+
final Iterator<String> fieldNames = node.fieldNames();
77+
while (fieldNames.hasNext()) {
78+
final String fieldName = fieldNames.next();
79+
if (bidderAliases.isSame(fieldName, bidderName)) {
80+
return node.get(fieldName);
81+
}
82+
}
83+
return null;
84+
}
85+
86+
private static void removeExtPrebidBidder(JsonNode bidderNode) {
87+
Optional.ofNullable(bidderNode.get(IMP_EXT))
88+
.map(extNode -> extNode.get(EXT_PREBID))
89+
.map(ObjectNode.class::cast)
90+
.ifPresent(ext -> ext.remove(EXT_PREBID_BIDDER));
91+
}
92+
93+
private static void removeImpExtPrebidImp(JsonNode mergedImpNode) {
94+
Optional.ofNullable(mergedImpNode.get(IMP_EXT))
95+
.map(extNode -> extNode.get(EXT_PREBID))
96+
.map(ObjectNode.class::cast)
97+
.ifPresent(prebid -> prebid.remove(EXT_PREBID_IMP));
98+
}
99+
}

src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtImpPrebid.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ public class ExtImpPrebid {
5656
* Defines the contract for bidrequest.imp[i].ext.prebid.passthrough
5757
*/
5858
JsonNode passthrough;
59+
60+
/**
61+
* Defines the contract for bidrequest.imp[i].ext.prebid.imp
62+
*/
63+
ObjectNode imp;
5964
}

src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.prebid.server.auction.ExchangeService;
1919
import org.prebid.server.auction.FpdResolver;
2020
import org.prebid.server.auction.GeoLocationServiceWrapper;
21+
import org.prebid.server.auction.ImpAdjuster;
2122
import org.prebid.server.auction.ImplicitParametersExtractor;
2223
import org.prebid.server.auction.InterstitialProcessor;
2324
import org.prebid.server.auction.IpAddressHelper;
@@ -111,6 +112,7 @@
111112
import org.prebid.server.util.VersionInfo;
112113
import org.prebid.server.util.system.CpuLoadAverageStats;
113114
import org.prebid.server.validation.BidderParamValidator;
115+
import org.prebid.server.validation.ImpValidator;
114116
import org.prebid.server.validation.RequestValidator;
115117
import org.prebid.server.validation.ResponseBidValidator;
116118
import org.prebid.server.validation.VideoRequestValidator;
@@ -245,6 +247,11 @@ FpdResolver fpdResolver(JacksonMapper mapper, JsonMerger jsonMerger) {
245247
return new FpdResolver(mapper, jsonMerger);
246248
}
247249

250+
@Bean
251+
ImpAdjuster impAdjuster(ImpValidator impValidator, JacksonMapper jacksonMapper, JsonMerger jsonMerger) {
252+
return new ImpAdjuster(jacksonMapper, jsonMerger, impValidator);
253+
}
254+
248255
@Bean
249256
OrtbTypesResolver ortbTypesResolver(JacksonMapper jacksonMapper, JsonMerger jsonMerger) {
250257
return new OrtbTypesResolver(logSamplingRate, jacksonMapper, jsonMerger);
@@ -819,6 +826,7 @@ ExchangeService exchangeService(
819826
StoredResponseProcessor storedResponseProcessor,
820827
PrivacyEnforcementService privacyEnforcementService,
821828
FpdResolver fpdResolver,
829+
ImpAdjuster impAdjuster,
822830
SupplyChainResolver supplyChainResolver,
823831
DebugResolver debugResolver,
824832
CompositeMediaTypeProcessor mediaTypeProcessor,
@@ -850,6 +858,7 @@ ExchangeService exchangeService(
850858
storedResponseProcessor,
851859
privacyEnforcementService,
852860
fpdResolver,
861+
impAdjuster,
853862
supplyChainResolver,
854863
debugResolver,
855864
mediaTypeProcessor,
@@ -989,18 +998,26 @@ VersionInfo versionInfo(JacksonMapper jacksonMapper) {
989998
return VersionInfo.create("git-revision.json", jacksonMapper);
990999
}
9911000

1001+
@Bean
1002+
ImpValidator impValidator(BidderParamValidator bidderParamValidator,
1003+
BidderCatalog bidderCatalog,
1004+
JacksonMapper mapper) {
1005+
1006+
return new ImpValidator(bidderParamValidator, bidderCatalog, mapper);
1007+
}
1008+
9921009
@Bean
9931010
RequestValidator requestValidator(
9941011
BidderCatalog bidderCatalog,
995-
BidderParamValidator bidderParamValidator,
1012+
ImpValidator impValidator,
9961013
Metrics metrics,
9971014
JacksonMapper mapper,
9981015
@Value("${logging.sampling-rate:0.01}") double logSamplingRate,
9991016
@Value("${auction.strict-app-site-dooh:false}") boolean enabledStrictAppSiteDoohValidation) {
10001017

10011018
return new RequestValidator(
10021019
bidderCatalog,
1003-
bidderParamValidator,
1020+
impValidator,
10041021
metrics,
10051022
mapper,
10061023
logSamplingRate,

0 commit comments

Comments
 (0)