Skip to content

Commit 50a74bb

Browse files
New Adagio Adapter (#4027)
1 parent 2d2d339 commit 50a74bb

File tree

12 files changed

+634
-0
lines changed

12 files changed

+634
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package org.prebid.server.bidder.adagio;
2+
3+
import com.iab.openrtb.request.BidRequest;
4+
import com.iab.openrtb.response.Bid;
5+
import com.iab.openrtb.response.BidResponse;
6+
import org.apache.commons.collections4.CollectionUtils;
7+
import org.prebid.server.bidder.Bidder;
8+
import org.prebid.server.bidder.model.BidderBid;
9+
import org.prebid.server.bidder.model.BidderCall;
10+
import org.prebid.server.bidder.model.BidderError;
11+
import org.prebid.server.bidder.model.HttpRequest;
12+
import org.prebid.server.bidder.model.Result;
13+
import org.prebid.server.exception.PreBidException;
14+
import org.prebid.server.json.DecodeException;
15+
import org.prebid.server.json.JacksonMapper;
16+
import org.prebid.server.proto.openrtb.ext.response.BidType;
17+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
18+
import org.prebid.server.util.BidderUtil;
19+
import org.prebid.server.util.HttpUtil;
20+
21+
import java.util.ArrayList;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import java.util.Objects;
25+
26+
public class AdagioBidder implements Bidder<BidRequest> {
27+
28+
private final String endpointUrl;
29+
private final JacksonMapper mapper;
30+
31+
public AdagioBidder(String endpointUrl, JacksonMapper mapper) {
32+
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
33+
this.mapper = Objects.requireNonNull(mapper);
34+
}
35+
36+
@Override
37+
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
38+
return Result.withValue(BidderUtil.defaultRequest(request, endpointUrl, mapper));
39+
}
40+
41+
@Override
42+
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
43+
final List<BidderError> errors = new ArrayList<>();
44+
try {
45+
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
46+
return Result.of(extractBids(bidResponse, errors), errors);
47+
} catch (DecodeException e) {
48+
return Result.withError(BidderError.badServerResponse(e.getMessage()));
49+
}
50+
}
51+
52+
private List<BidderBid> extractBids(BidResponse bidResponse, List<BidderError> errors) {
53+
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
54+
errors.add(BidderError.badServerResponse("empty seatbid array"));
55+
return Collections.emptyList();
56+
}
57+
58+
return bidResponse.getSeatbid().stream()
59+
.filter(Objects::nonNull)
60+
.flatMap(seatBid -> seatBid.getBid().stream()
61+
.filter(Objects::nonNull)
62+
.map(bid -> makeBid(bid, bidResponse.getCur(), seatBid.getSeat(), errors)))
63+
.filter(Objects::nonNull)
64+
.toList();
65+
}
66+
67+
private BidderBid makeBid(Bid bid, String currency, String seat, List<BidderError> errors) {
68+
try {
69+
final ExtBidPrebid extBidPrebid = parseBidExt(bid);
70+
return BidderBid.builder()
71+
.bid(bid)
72+
.type(getBidType(bid))
73+
.bidCurrency(currency)
74+
.videoInfo(extBidPrebid != null ? extBidPrebid.getVideo() : null)
75+
.seat(seat)
76+
.build();
77+
78+
} catch (PreBidException e) {
79+
errors.add(BidderError.badServerResponse(e.getMessage()));
80+
return null;
81+
}
82+
}
83+
84+
private ExtBidPrebid parseBidExt(Bid bid) {
85+
try {
86+
return mapper.mapper().convertValue(bid.getExt(), ExtBidPrebid.class);
87+
} catch (IllegalArgumentException e) {
88+
throw new PreBidException("bid.ext can not be parsed");
89+
}
90+
}
91+
92+
private static BidType getBidType(Bid bid) {
93+
return switch (bid.getMtype()) {
94+
case 1 -> BidType.banner;
95+
case 2 -> BidType.video;
96+
case 4 -> BidType.xNative;
97+
case null, default -> throw new PreBidException(
98+
"Could not define media type for impression: " + bid.getImpid());
99+
};
100+
}
101+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.prebid.server.proto.openrtb.ext.request.adagio;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Value;
5+
6+
@Value(staticConstructor = "of")
7+
public class ExtImpAdagio {
8+
9+
@JsonProperty("organizationId")
10+
String organizationId;
11+
12+
String placement;
13+
14+
String pagetype;
15+
16+
String category;
17+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.prebid.server.spring.config.bidder;
2+
3+
import org.prebid.server.bidder.BidderDeps;
4+
import org.prebid.server.bidder.adagio.AdagioBidder;
5+
import org.prebid.server.json.JacksonMapper;
6+
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
7+
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
8+
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
9+
import org.prebid.server.spring.env.YamlPropertySourceFactory;
10+
import org.springframework.beans.factory.annotation.Value;
11+
import org.springframework.boot.context.properties.ConfigurationProperties;
12+
import org.springframework.context.annotation.Bean;
13+
import org.springframework.context.annotation.Configuration;
14+
import org.springframework.context.annotation.PropertySource;
15+
16+
import jakarta.validation.constraints.NotBlank;
17+
18+
@Configuration
19+
@PropertySource(value = "classpath:/bidder-config/adagio.yaml", factory = YamlPropertySourceFactory.class)
20+
public class AdagioConfiguration {
21+
22+
private static final String BIDDER_NAME = "adagio";
23+
24+
@Bean("adagioConfigurationProperties")
25+
@ConfigurationProperties("adapters.adagio")
26+
BidderConfigurationProperties configurationProperties() {
27+
return new BidderConfigurationProperties();
28+
}
29+
30+
@Bean
31+
BidderDeps adagioBidderDeps(BidderConfigurationProperties adagioConfigurationProperties,
32+
@NotBlank @Value("${external-url}") String externalUrl,
33+
JacksonMapper mapper) {
34+
35+
return BidderDepsAssembler.forBidder(BIDDER_NAME)
36+
.withConfig(adagioConfigurationProperties)
37+
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
38+
.bidderCreator(config -> new AdagioBidder(config.getEndpoint(), mapper))
39+
.assemble();
40+
}
41+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
adapters:
2+
adagio:
3+
# Please deploy this config in each of your datacenters with the appropriate regional subdomain.
4+
# Replace the `REGION` by one of the value below:
5+
# - For AMER: las => (https://mp-las.4dex.io/pbserver)
6+
# - For EMEA: ams => (https://mp-ams.4dex.io/pbserver)
7+
# - For APAC: tyo => (https://mp-tyo.4dex.io/pbserver)
8+
endpoint: https://mp-REGION.4dex.io/pbserver
9+
ortb-version: "2.6"
10+
endpoint-compression: gzip
11+
meta-info:
12+
maintainer-email: dev@adagio.io
13+
app-media-types:
14+
- banner
15+
- video
16+
- native
17+
site-media-types:
18+
- banner
19+
- video
20+
- native
21+
supported-vendors:
22+
vendor-id: 617
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "Adagio Adapter Params",
4+
"description": "A schema which validates params accepted by the Adagio adapter",
5+
"type": "object",
6+
"properties": {
7+
"organizationId": {
8+
"type": "string",
9+
"description": "Id of the Organization. Handed out by Adagio."
10+
},
11+
"placement": {
12+
"type": "string",
13+
"description": "Refers to the placement of an adunit in a page. Must not contain any information about the type of device.",
14+
"maxLength": 30
15+
},
16+
"pagetype": {
17+
"type": "string",
18+
"description": "Describes what kind of content will be present in the page.",
19+
"maxLength": 30
20+
},
21+
"category": {
22+
"type": "string",
23+
"description": "Category of the content displayed in the page.",
24+
"maxLength": 30
25+
}
26+
},
27+
"required": [
28+
"organizationId",
29+
"placement"
30+
]
31+
}

0 commit comments

Comments
 (0)