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

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed the requirement to emit warning in debug mode, shouldn't we add the warning messages to the response?

}

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)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I see, bidder can be an alias at the request level, so we need to resolve that mapping first.

.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));
Comment on lines +83 to +90
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        final boolean extIgsAePresent = Optional.ofNullable(ext)
                .map(extNode -> extNode.get(EXT_IGS))
                .filter(JsonNode::isArray)
                .stream()
                .flatMap(extNode -> StreamUtil.asStream(extNode.spliterator()))
                .filter(Objects::nonNull)
                .anyMatch(igsElementNode -> igsElementNode.has(EXT_AE));


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.
*/
Comment on lines -50 to -53
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please keep these comments)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't comment code. Only in super tricky situations, which is not the case.

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