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

Aax Bidder: Update #1937

Merged
merged 23 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from 21 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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@
<version>${maven-surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<launchContainers>false</launchContainers>
<launchContainers>true</launchContainers>
</systemPropertyVariables>
<skipTests>${skipUnitTests}</skipTests>
</configuration>
Expand Down
141 changes: 141 additions & 0 deletions src/main/java/org/prebid/server/bidder/aax/AaxBidder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.prebid.server.bidder.aax;

import com.fasterxml.jackson.databind.JsonNode;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.response.Bid;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import io.vertx.core.http.HttpMethod;
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.bidder.Bidder;
import org.prebid.server.bidder.model.BidderBid;
import org.prebid.server.bidder.model.BidderCall;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.exception.PreBidException;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class AaxBidder implements Bidder<BidRequest> {

private final String endpointUrl;
private final JacksonMapper mapper;

private static final String USD_CURRENCY = "USD";

public AaxBidder(String endpointUrl, JacksonMapper mapper) {
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.mapper = Objects.requireNonNull(mapper);
}

@Override
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest bidRequest) {
return Result.withValue(
HttpRequest.<BidRequest>builder()
.method(HttpMethod.POST)
.uri(endpointUrl)
.headers(HttpUtil.headers())
.body(mapper.encodeToBytes(bidRequest))
.payload(bidRequest)
.build());
}

@Override
public final Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
final List<BidderError> errors = new ArrayList<>();
try {
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
List<BidderBid> bidderBids = extractBids(httpCall.getRequest().getPayload(), bidResponse, errors);
return Result.of(bidderBids, errors);
} catch (DecodeException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}
}

private List<BidderBid> extractBids(BidRequest bidRequest, BidResponse bidResponse, List<BidderError> errorList) {
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
return Collections.emptyList();
}
return bidsFromResponse(bidRequest, bidResponse, errorList);
}

private List<BidderBid> bidsFromResponse(BidRequest bidRequest,
BidResponse bidResponse,
List<BidderError> errorList) {
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved

return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(SeatBid::getBid)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.map(bid -> resolveBidderBid(bid, bidRequest.getImp(), errorList))
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

private BidderBid resolveBidderBid(Bid bid, List<Imp> imps, List<BidderError> errors) {
final BidType bidType;
try {
bidType = getBidType(bid, imps);
} catch (PreBidException e) {
errors.add(BidderError.badServerResponse(e.getMessage()));
return null;
}
return BidderBid.of(bid, bidType, USD_CURRENCY);
}

private BidType getBidType(Bid bid, List<Imp> imps) {
final JsonNode aaxExtBid = bid.getExt() != null ? bid.getExt().get("adCodeType") : null;
final String mediaType = aaxExtBid != null ? aaxExtBid.asText() : null;
final BidType bidTypeFromExt = mediaType != null ? bidTypeFromString(mediaType) : null;

if (bidTypeFromExt != null) {
return bidTypeFromExt;
}

BidType bidType = null;
int countType = 0;
for (Imp imp : imps) {
if (imp.getId().equals(bid.getImpid())) {
if (imp.getBanner() != null) {
countType++;
bidType = BidType.banner;
}
if (imp.getVideo() != null) {
countType++;
bidType = BidType.video;
}
if (imp.getXNative() != null) {
countType++;
bidType = BidType.xNative;
}
}
}

if (countType != 1) {
throw new PreBidException(String.format("Unable to fetch mediaType in multi-format: %s", bid.getImpid()));
}

return bidType;
}
CTMBNara marked this conversation as resolved.
Show resolved Hide resolved

private BidType bidTypeFromString(String mediaType) {
return switch (mediaType) {
case "banner" -> BidType.banner;
case "native" -> BidType.xNative;
case "video" -> BidType.video;
default -> null;
};
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.prebid.server.spring.config.bidder;

import org.prebid.server.bidder.BidderDeps;
import org.prebid.server.bidder.GenericBidder;
import org.prebid.server.bidder.aax.AaxBidder;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
Expand Down Expand Up @@ -37,7 +37,7 @@ BidderDeps aaxBidderDeps(BidderConfigurationProperties aaxConfigurationPropertie
return BidderDepsAssembler.forBidder(BIDDER_NAME)
.withConfig(aaxConfigurationProperties)
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
.bidderCreator(config -> new GenericBidder(resolveEndpoint(config.getEndpoint(), externalUrl), mapper))
.bidderCreator(config -> new AaxBidder(resolveEndpoint(config.getEndpoint(), externalUrl), mapper))
.assemble();
}

Expand Down
1 change: 1 addition & 0 deletions src/main/resources/bidder-config/aax.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
adapters:
aax:
endpoint: https://prebid.aaxads.com/rtb/pb/aax-prebid?src={{PREBID_SERVER_ENDPOINT}}
modifyingVastXmlAllowed: true
meta-info:
maintainer-email: [email protected]
app-media-types:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class HibernateRepositoryService {
properties.setProperty("hibernate.show_sql", "false")
properties.setProperty("hibernate.format_sql", "false")


def configuration = new Configuration()
configuration.addAnnotatedClass(Account)
configuration.addAnnotatedClass(S2sConfig)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.prebid.server.functional.testcontainers

import io.vertx.core.logging.Logger
import io.vertx.core.logging.LoggerFactory
import org.prebid.server.auction.ExchangeService
import org.prebid.server.functional.service.PrebidServerService
import org.prebid.server.functional.testcontainers.container.NetworkServiceContainer
import org.prebid.server.functional.testcontainers.container.PrebidServerContainer
import org.prebid.server.functional.util.SystemProperties
import org.testcontainers.containers.output.OutputFrame

import static org.prebid.server.functional.util.SystemProperties.USE_FIXED_CONTAINER_PORTS

Expand All @@ -12,6 +16,7 @@ class PbsServiceFactory {

private static final Map<Map<String, String>, PrebidServerContainer> containers = [:]
private static final int MAX_CONTAINER_COUNT = maxContainerCount
private static final Logger logger = LoggerFactory.getLogger(ExchangeService.class);

private final NetworkServiceContainer networkServiceContainer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class PrebidServerContainer extends GenericContainer<PrebidServerContainer> {
<< PbsConfig.mySqlConfig
withConfig(commonConfig)
withConfig(customConfig)
withStartupAttempts(5)
}

private void withFixedPorts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast
import org.prebid.server.functional.model.response.auction.Adm
import org.prebid.server.functional.model.response.auction.BidResponse
import org.prebid.server.functional.util.PBSUtils
import spock.lang.Retry

class CacheSpec extends BaseSpec {

Expand Down Expand Up @@ -68,6 +69,7 @@ class CacheSpec extends BaseSpec {
assert metrics["account.${accountId}.prebid_cache.requests.ok" as String] == 1
}

@Retry(condition = { prebidCache.requestCount == 0 })
def "PBS should cache bids when targeting is specified"() {
given: "Default BidRequest with cache, targeting"
def bidRequest = BidRequest.defaultBidRequest
Expand Down
Loading