Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Transition PAAPI parameters #3670

Merged
merged 27 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1810e87
Added new PAA iab model.
And1sS Dec 16, 2024
abd3104
PAA WIP.
And1sS Dec 20, 2024
ebfa6df
Refactoring.
And1sS Dec 20, 2024
e4a45ef
Refactoring.
And1sS Dec 26, 2024
824d279
Refactoring.
And1sS Dec 26, 2024
4b60b51
Partly fixed unit tests.
And1sS Jan 7, 2025
5bf42c6
Fixed unit tests.
And1sS Jan 7, 2025
81d8c77
Added unit tests for BidResponseCreator and HttpBidderRequester
And1sS Jan 8, 2025
5d6d88b
Added igs.ae mapping.
And1sS Jan 9, 2025
4ca36ba
Removed TODOs.
And1sS Jan 9, 2025
9e492ba
Fixed styling.
And1sS Jan 9, 2025
8333f7c
Fixed naming.
And1sS Jan 9, 2025
9292540
Merge branch 'master' into feature/paa
And1sS Jan 10, 2025
b0c7f31
Fixes after merging master
And1sS Jan 10, 2025
85208f5
Fixed IxTest.
And1sS Jan 10, 2025
3882deb
Made paa format default to original.
And1sS Jan 14, 2025
0841723
Added missing validations.
And1sS Jan 14, 2025
032f15f
Fixed inconsistent unit test.
And1sS Jan 14, 2025
5163003
Merge branch 'master' into feature/paa
And1sS Jan 14, 2025
7fd613e
Fixed igi validations.
And1sS Jan 15, 2025
bfffd2f
Fixed styling.
And1sS Jan 15, 2025
d5d45c3
Added bidRequest level alias resolving and response level debug warni…
And1sS Jan 24, 2025
c466359
Refactored ImpAdjuster.
And1sS Jan 24, 2025
ce1d57f
Now paa debug warnings utilize debugEnabled flag.
And1sS Jan 24, 2025
d16a64b
Added metrics.
And1sS Jan 27, 2025
7ea648e
Test: `Transition PAAPI parameters` (#3634)
marki1an Jan 27, 2025
77df115
Merge branch 'refs/heads/master' into feature/paa
osulzhenko Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 138 additions & 14 deletions src/main/java/org/prebid/server/auction/BidResponseCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.prebid.server.auction.model.CachedDebugLog;
import org.prebid.server.auction.model.CategoryMappingResult;
import org.prebid.server.auction.model.MultiBidConfig;
import org.prebid.server.auction.model.PaaFormat;
import org.prebid.server.auction.model.TargetingInfo;
import org.prebid.server.auction.model.debug.DebugContext;
import org.prebid.server.auction.requestfactory.Ortb2ImplicitParametersResolver;
Expand Down Expand Up @@ -61,6 +62,9 @@
import org.prebid.server.identity.IdGeneratorType;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.log.ConditionalLogger;
import org.prebid.server.log.Logger;
import org.prebid.server.log.LoggerFactory;
import org.prebid.server.proto.openrtb.ext.request.ExtImp;
import org.prebid.server.proto.openrtb.ext.request.ExtImpAuctionEnvironment;
import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid;
Expand All @@ -82,6 +86,10 @@
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError;
import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace;
import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall;
import org.prebid.server.proto.openrtb.ext.response.ExtIgi;
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgb;
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs;
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt;
import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache;
import org.prebid.server.proto.openrtb.ext.response.ExtResponseDebug;
import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInfrastructure;
Expand Down Expand Up @@ -118,6 +126,9 @@

public class BidResponseCreator {

private static final Logger logger = LoggerFactory.getLogger(BidResponseCreator.class);
private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger);

private static final String CACHE = "cache";
private static final String PREBID_EXT = "prebid";
private static final Integer DEFAULT_BID_LIMIT_MIN = 1;
Expand All @@ -127,6 +138,7 @@ public class BidResponseCreator {
private static final String TARGETING_ENV_APP_VALUE = "mobile-app";
private static final String TARGETING_ENV_AMP_VALUE = "amp";

private final double logSamplingRate;
private final CoreCacheService coreCacheService;
private final BidderCatalog bidderCatalog;
private final VastModifier vastModifier;
Expand All @@ -146,7 +158,8 @@ public class BidResponseCreator {
private final String cachePath;
private final String cacheAssetUrlTemplate;

public BidResponseCreator(CoreCacheService coreCacheService,
public BidResponseCreator(double logSamplingRate,
CoreCacheService coreCacheService,
BidderCatalog bidderCatalog,
VastModifier vastModifier,
EventsService eventsService,
Expand Down Expand Up @@ -176,9 +189,11 @@ public BidResponseCreator(CoreCacheService coreCacheService,
this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl);
this.cacheDefaultProperties = Objects.requireNonNull(cacheDefaultProperties);

this.logSamplingRate = logSamplingRate;

cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate());
cacheHost = Objects.requireNonNull(coreCacheService.getEndpointHost());
cachePath = Objects.requireNonNull(coreCacheService.getEndpointPath());
cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate());
}

private static int validateTruncateAttrChars(int truncateAttrChars) {
Expand Down Expand Up @@ -418,7 +433,8 @@ private List<BidderResponseInfo> toBidderResponseInfos(CategoryMappingResult cat
seatBid.getHttpCalls(),
seatBid.getErrors(),
seatBid.getWarnings(),
seatBid.getFledgeAuctionConfigs());
seatBid.getFledgeAuctionConfigs(),
seatBid.getIgi());

result.add(BidderResponseInfo.of(bidder, bidderSeatBidInfo, bidderResponse.getResponseTime()));
}
Expand Down Expand Up @@ -778,16 +794,20 @@ private ExtBidResponse toExtBidResponse(List<BidderResponseInfo> bidderResponseI

final Map<String, Integer> responseTimeMillis = toResponseTimes(bidderResponseInfos, cacheResult);

final ExtBidResponseFledge extBidResponseFledge = toExtBidResponseFledge(bidderResponseInfos, auctionContext);
final PaaResult paaResult = toPaaOutput(bidderResponseInfos, auctionContext);
final List<ExtIgi> igi = paaResult.igis();
final ExtBidResponseFledge fledge = paaResult.fledge();

final ExtBidResponsePrebid prebid = toExtBidResponsePrebid(
auctionTimestamp, auctionContext.getBidRequest(), extBidResponseFledge);
auctionTimestamp, auctionContext.getBidRequest(), fledge);

return ExtBidResponse.builder()
.debug(extResponseDebug)
.errors(errors)
.warnings(warnings)
.responsetimemillis(responseTimeMillis)
.tmaxrequest(auctionContext.getBidRequest().getTmax())
.igi(igi)
.prebid(prebid)
.build();
}
Expand All @@ -809,17 +829,107 @@ private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp,
.build();
}

private ExtBidResponseFledge toExtBidResponseFledge(List<BidderResponseInfo> bidderResponseInfos,
AuctionContext auctionContext) {
private PaaResult toPaaOutput(List<BidderResponseInfo> bidderResponseInfos, AuctionContext auctionContext) {
final PaaFormat paaFormat = resolvePaaFormat(auctionContext);
final List<ExtIgi> igis = extractIgis(bidderResponseInfos);
final List<ExtIgi> extIgi = paaFormat == PaaFormat.IAB && !igis.isEmpty() ? igis : null;

final List<FledgeAuctionConfig> fledgeConfigs = paaFormat == PaaFormat.ORIGINAL
? toOriginalFledgeFormat(igis)
: Collections.emptyList();

// TODO: Remove after transition period
final List<Imp> imps = auctionContext.getBidRequest().getImp();
final List<FledgeAuctionConfig> fledgeConfigs = bidderResponseInfos.stream()
.flatMap(bidderResponseInfo -> fledgeConfigsForBidder(bidderResponseInfo, imps))
final List<FledgeAuctionConfig> deprecatedFledgeConfigs = bidderResponseInfos.stream()
.flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps))
.toList();

final List<FledgeAuctionConfig> combinedFledgeConfigs = ListUtils.union(deprecatedFledgeConfigs, fledgeConfigs);
final ExtBidResponseFledge extBidResponseFledge = combinedFledgeConfigs.isEmpty()
? null
: ExtBidResponseFledge.of(combinedFledgeConfigs);

return new PaaResult(extIgi, extBidResponseFledge);
}

private List<ExtIgi> extractIgis(List<BidderResponseInfo> bidderResponseInfos) {
return bidderResponseInfos.stream()
.flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream()
.map(igi -> prepareExtIgi(igi, responseInfo.getBidder())))
.filter(Objects::nonNull)
.toList();
}

private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) {
if (igi == null) {
return null;
}

final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid());
if (shouldDropIgb) {
conditionalLogger.warn("ExtIgi with absent impId from bidder: " + bidder, logSamplingRate);
And1sS marked this conversation as resolved.
Show resolved Hide resolved
}

final List<ExtIgiIgs> updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder);
final List<ExtIgiIgs> preparedIgs = updatedIgs.isEmpty() ? null : updatedIgs;
final List<ExtIgiIgb> preparedIgb = shouldDropIgb ? null : igi.getIgb();

return ObjectUtils.anyNotNull(preparedIgs, preparedIgb)
? igi.toBuilder().igs(preparedIgs).igb(preparedIgb).build()
: null;
}

private List<ExtIgiIgs> prepareExtIgiIgs(List<ExtIgiIgs> igiIgs, String bidder) {
if (igiIgs == null) {
return Collections.emptyList();
}

final List<ExtIgiIgs> preparedIgiIgs = new ArrayList<>();
for (ExtIgiIgs extIgiIgs : igiIgs) {
if (extIgiIgs == null) {
continue;
}

if (StringUtils.isEmpty(extIgiIgs.getImpId())) {
conditionalLogger.warn("ExtIgiIgs with absent impId from bidder: " + bidder, logSamplingRate);
continue;
}

if (extIgiIgs.getConfig() == null) {
conditionalLogger.warn("ExtIgiIgs with absent config from bidder: " + bidder, logSamplingRate);
continue;
}

final ExtIgiIgs preparedExtIgiIgs = extIgiIgs.toBuilder()
.ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder)))
And1sS marked this conversation as resolved.
Show resolved Hide resolved
.build();

preparedIgiIgs.add(preparedExtIgiIgs);
}

return preparedIgiIgs;
}

private List<FledgeAuctionConfig> toOriginalFledgeFormat(List<ExtIgi> igis) {
return igis.stream()
.map(ExtIgi::getIgs)
.flatMap(Collection::stream)
.map(BidResponseCreator::extIgiIgsToFledgeConfig)
.toList();
return !fledgeConfigs.isEmpty() ? ExtBidResponseFledge.of(fledgeConfigs) : null;
}

private Stream<FledgeAuctionConfig> fledgeConfigsForBidder(BidderResponseInfo bidderResponseInfo, List<Imp> imps) {
private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs) {
return FledgeAuctionConfig.builder()
.bidder(extIgiIgs.getExt().getBidder())
.adapter(extIgiIgs.getExt().getAdapter())
.impId(extIgiIgs.getImpId())
.config(extIgiIgs.getConfig())
.build();
}

private Stream<FledgeAuctionConfig> toDeprecatedFledgeConfigs(BidderResponseInfo bidderResponseInfo,
List<Imp> imps) {

return Optional.ofNullable(bidderResponseInfo.getSeatBid().getFledgeAuctionConfigs())
.stream()
.flatMap(Collection::stream)
Expand All @@ -836,10 +946,10 @@ private boolean validateFledgeConfig(FledgeAuctionConfig fledgeAuctionConfig, Li
return fledgeEnabled == ExtImpAuctionEnvironment.ON_DEVICE_IG_AUCTION_FLEDGE;
}

private static FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidderName) {
private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidder) {
return fledgeConfig.toBuilder()
.bidder(bidderName)
.adapter(bidderName)
.bidder(bidder)
.adapter(bidderCatalog.resolveBaseBidder(bidder))
.build();
}

Expand Down Expand Up @@ -1154,6 +1264,17 @@ private static Map<String, Integer> toResponseTimes(Collection<BidderResponseInf
return responseTimeMillis;
}

private static PaaFormat resolvePaaFormat(AuctionContext auctionContext) {
return Optional.of(auctionContext.getBidRequest())
.map(BidRequest::getExt)
.map(ExtRequest::getPrebid)
.map(ExtRequestPrebid::getPaaFormat)
.or(() -> Optional.ofNullable(auctionContext.getAccount())
.map(Account::getAuction)
.map(AccountAuctionConfig::getPaaFormat))
.orElse(PaaFormat.ORIGINAL);
}

/**
* Returns {@link BidResponse} based on list of {@link BidderResponse}s and {@link CacheServiceResult}.
*/
Expand Down Expand Up @@ -1800,4 +1921,7 @@ private <T> T convertValue(JsonNode jsonNode, String key, Class<T> typeClass) {
return null;
}
}

private record PaaResult(List<ExtIgi> igis, ExtBidResponseFledge fledge) {
}
}
31 changes: 31 additions & 0 deletions src/main/java/org/prebid/server/auction/ImpAdjuster.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
package org.prebid.server.auction;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.Imp;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.json.JsonMerger;
import org.prebid.server.validation.ImpValidator;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.StreamSupport;

public class ImpAdjuster {

private static final String IMP_EXT = "ext";
private static final String EXT_AE = "ae";
private static final String EXT_IGS = "igs";
private static final String EXT_PREBID = "prebid";
private static final String EXT_PREBID_BIDDER = "bidder";
private static final String EXT_PREBID_IMP = "imp";
Expand All @@ -33,6 +39,8 @@ public ImpAdjuster(JacksonMapper jacksonMapper,
}

public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, List<String> debugMessages) {
setAeParams(originalImp.getExt());

final JsonNode impExtPrebidImp = bidderParamsFromImpExtPrebidImp(originalImp.getExt());
if (impExtPrebidImp == null) {
return originalImp;
Expand Down Expand Up @@ -65,6 +73,29 @@ public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, L
}
}

private void setAeParams(ObjectNode ext) {
final int extAe = Optional.ofNullable(ext)
.map(extNode -> extNode.get(EXT_AE))
.filter(JsonNode::isInt)
.map(JsonNode::asInt)
.orElse(-1);

final boolean extIgsAePresent = Optional.ofNullable(ext)
.map(extNode -> extNode.get(EXT_IGS))
.filter(JsonNode::isArray)
.map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList())
.stream()
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.anyMatch(igsElementNode -> igsElementNode.has(EXT_AE));
And1sS marked this conversation as resolved.
Show resolved Hide resolved

if (!extIgsAePresent && (extAe == 0 || extAe == 1)) {
final ArrayNode extIgs = jacksonMapper.mapper().createArrayNode();
extIgs.add(jacksonMapper.mapper().createObjectNode().set(EXT_AE, IntNode.valueOf(extAe)));
ext.set(EXT_IGS, extIgs);
}
}

private static JsonNode bidderParamsFromImpExtPrebidImp(ObjectNode ext) {
return Optional.ofNullable(ext)
.map(extNode -> extNode.get(EXT_PREBID))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ public BidRejectionTracker(String bidder, Set<String> involvedImpIds, double log
rejectedBids = new HashMap<>();
}

/**
* Restores ONLY imps from rejection, rejected bids are preserved for analytics.
* A bid can be rejected only once.
*/
And1sS marked this conversation as resolved.
Show resolved Hide resolved
public void succeed(Collection<BidderBid> bids) {
bids.stream()
.map(BidderBid::getBid)
Expand Down Expand Up @@ -124,10 +120,6 @@ public void rejectAllImps(BidRejectionReason reason) {
involvedImpIds.forEach(impId -> rejectImp(impId, reason));
}

/**
* If an impression has at least one valid bid, it's not considered rejected.
* If no valid bids are returned for the impression, only the first one rejected reason will be returned
*/
public Map<String, BidRejectionReason> getRejectedImps() {
final Map<String, BidRejectionReason> rejectedImpIds = new HashMap<>();
for (String impId : involvedImpIds) {
Expand All @@ -144,9 +136,6 @@ public Map<String, BidRejectionReason> getRejectedImps() {
return rejectedImpIds;
}

/**
* Bid is absent for the non-bid code from 0 to 299
*/
public Map<String, List<Pair<BidderBid, BidRejectionReason>>> getRejectedBids() {
final Map<String, List<Pair<BidderBid, BidRejectionReason>>> missingImpIds = new HashMap<>();
for (String impId : involvedImpIds) {
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/prebid/server/auction/model/PaaFormat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.prebid.server.auction.model;

import com.fasterxml.jackson.annotation.JsonProperty;

public enum PaaFormat {

@JsonProperty("original")
ORIGINAL,

@JsonProperty("iab")
IAB
}
Loading
Loading