Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# From https://github.com/microsoft/vscode-dev-containers/blob/master/containers/go/.devcontainer/Dockerfile
ARG VARIANT="21-jdk-bookworm"
ARG VARIANT="25-jdk-trixie"
FROM mcr.microsoft.com/vscode/devcontainers/java:${VARIANT}
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"dockerfile": "Dockerfile",
"args": {
// Update the VARIANT arg to pick a version of Java
"VARIANT": "21-jdk-bookworm",
"VARIANT": "25-jdk-trixie",
}
},
"containerEnv": {
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
java-version: 25

- name: Cache Maven packages
uses: actions/cache@v5
Expand All @@ -52,7 +52,7 @@ jobs:

- name: Build with Maven
if: matrix.build-mode == 'manual'
run: mvn -B package --file extra/pom.xml
run: mvn -B clean package -DskipUnitTests --file extra/pom.xml

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docker-image-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 21 ]
java: [ 25 ]
dockerfile-path: [ Dockerfile, Dockerfile-modules ]
include:
- dockerfile-path: Dockerfile
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-functional-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

strategy:
matrix:
java: [ 21 ]
java: [ 25 ]

steps:
- uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-java-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

strategy:
matrix:
java: [ 21 ]
java: [ 25 ]

steps:
- uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-module-functional-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

strategy:
matrix:
java: [ 21 ]
java: [ 25 ]

steps:
- uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-asset-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ 21 ]
java: [ 25 ]
steps:
- uses: actions/checkout@v5
- name: Set up JDK
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM amazoncorretto:21.0.8-al2023
FROM amazoncorretto:25.0.3-al2023-headless

WORKDIR /app/prebid-server

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile-modules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM amazoncorretto:21.0.8-al2023
FROM amazoncorretto:25.0.3-al2023-headless

WORKDIR /app/prebid-server

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Follow next steps to create JAR file which can be deployed locally.

- Install prerequsites
- Java SDK: Oracle's or Corretto. Let us know if there's a distribution PBS-Java doesn't work with.
- Java SDK Version: 21
- Java SDK Version: 25
- Maven

- Clone the project:
Expand Down
7 changes: 4 additions & 3 deletions docs/config-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ This parameter exists to allow to change the location of the directory Vert.x wi
- `http-client.connect-timeout-ms` - set the connect timeout.
- `http-client.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make http client more robust.
- `http-client.circuit-breaker.opening-threshold` - the number of failures before opening the circuit.
- `http-client.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached.
- `http-client.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000)
- `http-client.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try.
- `http-client.circuit-breaker.idle-expire-hours` - idle time to clean the circuit breaker up.
- `http-client.use-compression` - if equals to `true` httpclient compression is enabled for requests (see [also](https://vertx.io/docs/apidocs/io/vertx/core/http/HttpClientOptions.html#setTryUseCompression-boolean-))
Expand Down Expand Up @@ -323,6 +323,7 @@ For filesystem data source available next options:

For database data source available next options:
- `settings.database.type` - type of database to be used: `mysql` or `postgres`.
- `settings.database.ssl-mode` - type of ssl mode to be used: `disabled`, `preferred` or `required`
- `settings.database.host` - database destination host.
- `settings.database.port` - database destination port.
- `settings.database.dbname` - database name.
Expand All @@ -338,7 +339,7 @@ For database data source available next options:
- `settings.database.stored-responses-query` - the SQL query to fetch stored responses.
- `settings.database.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make database client more robust.
- `settings.database.circuit-breaker.opening-threshold` - the number of failures before opening the circuit.
- `settings.database.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached.
- `settings.database.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000)
- `settings.database.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try.

For HTTP data source available next options:
Expand Down Expand Up @@ -473,7 +474,7 @@ If not defined in config all other Health Checkers would be disabled and endpoin
- `geolocation.enabled` - if equals to `true` the geo location service will be used to determine the country for client request.
- `geolocation.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make geo location client more robust.
- `geolocation.circuit-breaker.opening-threshold` - the number of failures before opening the circuit.
- `geolocation.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached.
- `geolocation.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000)
- `geolocation.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try.
- `geolocation.type` - set the geo location service provider, can be `maxmind` or custom provided by hosting company.
- `geolocation.maxmind` - section for [MaxMind](https://www.maxmind.com) configuration as geo location service provider.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,83 +55,50 @@ public void disableScan() {
}

public Future<BidsScanResult> submitBids(RedisBidsData bids) {
final Promise<BidsScanResult> scanResult = Promise.promise();

final RedisAPI readRedisNodeAPI = this.readRedisNode.getRedisAPI();
final boolean shouldSubmit = !isScanDisabled
&& readRedisNodeAPI != null && !bids.getBresps().isEmpty();

if (shouldSubmit) {
readRedisNodeAPI.get("function_submit_bids", submitHash -> {
final Object submitHashResult = submitHash.result();
if (submitHashResult != null) {
final List<String> readArgs = List.of(
submitHashResult.toString(),
"0",
toBidsAsJson(bids),
apiKey,
"true");

readRedisNodeAPI.evalsha(readArgs, response -> {
if (response.result() != null) {
final BidsScanResult parserResult = redisParser
.parseBidsScanResult(response.result().toString());
final boolean isAnyRoSkipped = parserResult.getBidScanResults()
.stream().anyMatch(BidScanResult::isRoSkipped);

if (isAnyRoSkipped) {
reSubmitBidsToWriteNode(readArgs, scanResult);
} else {
scanResult.complete(parserResult);
}
} else {
scanResult.complete(getEmptyScanResult());
}
});
} else {
scanResult.complete(getEmptyScanResult());
}
});

return scanResult.future();
if (isScanDisabled || readRedisNodeAPI == null || bids.getBresps().isEmpty()) {
return Future.succeededFuture(getEmptyScanResult());
}

return Future.succeededFuture(getEmptyScanResult());
return readRedisNodeAPI.get("function_submit_bids")
.map(Response::toString)
.map(response -> List.of(response, "0", toBidsAsJson(bids), apiKey, "true"))
.compose(args -> scanBids(args, readRedisNodeAPI))
.otherwise(ignored -> getEmptyScanResult());
}

private Future<BidsScanResult> scanBids(List<String> args, RedisAPI redisAPI) {
return redisAPI.evalsha(args)
.map(Response::toString)
.map(redisParser::parseBidsScanResult)
.compose(parsedResult -> parsedResult.getBidScanResults()
.stream().anyMatch(BidScanResult::isRoSkipped)
? reSubmitBidsToWriteNode(args)
: Future.succeededFuture(parsedResult));
}

private void reSubmitBidsToWriteNode(List<String> readArgs, Promise<BidsScanResult> scanResult) {
private Future<BidsScanResult> reSubmitBidsToWriteNode(List<String> readArgs) {
final RedisAPI writeRedisAPI = this.writeRedisNode.getRedisAPI();
if (writeRedisAPI != null) {
final List<String> writeArgs = readArgs.stream().limit(4).toList();
writeRedisAPI.evalsha(writeArgs, response -> {
if (response.result() != null) {
final BidsScanResult parserResult = redisParser
.parseBidsScanResult(response.result().toString());

scanResult.complete(parserResult);
} else {
scanResult.complete(getEmptyScanResult());
}
});
} else {
scanResult.complete(getEmptyScanResult());
if (writeRedisAPI == null) {
return Future.succeededFuture(getEmptyScanResult());
}

final List<String> writeArgs = readArgs.stream().limit(4).toList();
return writeRedisAPI.evalsha(writeArgs)
.map(Response::toString)
.map(redisParser::parseBidsScanResult);
}

public Future<Boolean> isScanDisabledFlag() {
final RedisAPI redisAPI = this.readRedisNode.getRedisAPI();
final Promise<Boolean> isDisabled = Promise.promise();

if (redisAPI != null) {
redisAPI.get("scan-disabled", scanDisabledValue -> {
final Response scanDisabled = scanDisabledValue.result();
isDisabled.complete(scanDisabled != null && "true".equals(scanDisabled.toString()));
});

return isDisabled.future();
if (redisAPI == null) {
return Future.succeededFuture(true);
}

return Future.succeededFuture(true);
return redisAPI.get("scan-disabled")
.map(Response::toString)
.map(Boolean::parseBoolean)
.otherwise(false);
}

private String toBidsAsJson(RedisBidsData bids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public RedisAPI getRedisAPI() {
*/
private void createRedisClient(Handler<AsyncResult<RedisConnection>> handler, boolean isReconnect) {
Redis.createClient(vertx, options)
.connect(onConnect -> {
.connect()
.onComplete(onConnect -> {
if (onConnect.succeeded()) {
connection = onConnect.result();
connection.exceptionHandler(e -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.maxmind.geoip2.DatabaseReader;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.file.FileSystem;
import io.vertx.core.file.OpenOptions;
Expand Down Expand Up @@ -45,11 +44,10 @@ public DatabaseReaderFactory(GreenbidsRealTimeDataProperties properties, Vertx v
}

@Override
public void initialize(Promise<Void> initializePromise) {
downloadAndExtract()
public Future<Void> initialize() {
return downloadAndExtract()
.onSuccess(databaseReaderRef::set)
.<Void>mapEmpty()
.onComplete(initializePromise);
.mapEmpty();
}

private Future<DatabaseReader> downloadAndExtract() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.exception.InvalidRequestException;
import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl;
import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience;
Expand Down Expand Up @@ -70,14 +71,15 @@ private ObjectNode targetingToObjectNode(List<Audience> targeting) {

for (Audience audience : targeting) {
final List<AudienceId> ids = audience.getIds();
if (CollectionUtils.isEmpty(ids)) {
final String keyspace = audience.getKeyspace();
if (CollectionUtils.isEmpty(ids) || StringUtils.isEmpty(keyspace)) {
continue;
}

final String joinedIds = ids.stream()
.map(AudienceId::getId)
.collect(Collectors.joining(","));
node.putIfAbsent(audience.getKeyspace(), TextNode.valueOf(joinedIds));
node.putIfAbsent(keyspace, TextNode.valueOf(joinedIds));
}

return node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import io.vertx.core.http.impl.headers.HeadersMultiMap;
import io.vertx.core.http.HttpHeaders;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.execution.timeout.Timeout;
Expand Down Expand Up @@ -69,7 +69,7 @@ private String resolveEndpoint(String tenant, String origin) {
}

private static MultiMap headers(OptableTargetingProperties properties, List<String> ips, String userAgent) {
final MultiMap headers = HeadersMultiMap.headers()
final MultiMap headers = HttpHeaders.headers()
.add(HttpUtil.ACCEPT_HEADER, "application/json");

if (userAgent != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import io.vertx.core.MultiMap;
import io.vertx.core.http.impl.headers.HeadersMultiMap;
import io.vertx.core.http.HttpHeaders;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
Expand Down Expand Up @@ -193,7 +193,7 @@ protected Device givenDevice() {
}

protected HttpClientResponse givenSuccessHttpResponse(String fileName) {
final MultiMap headers = HeadersMultiMap.headers().add("Content-Type", "application/json");
final MultiMap headers = HttpHeaders.headers().add("Content-Type", "application/json");
return HttpClientResponse.of(HttpStatus.SC_OK, headers, givenBodyFromFile(fileName));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.prebid.server.hooks.modules.optable.targeting.v1.core;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.response.BidResponse;
import org.junit.jupiter.api.Test;
import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl;
import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience;
Expand All @@ -10,10 +11,30 @@

import java.util.List;

import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;

public class BidResponseEnricherTest extends BaseOptableTest {

@Test
public void shouldSkipEmptyKeyspaceWhileEnrichingBidResponse() {
// given
final BidResponse bidResponse = givenBidResponse();
final AuctionResponsePayload auctionResponsePayload = AuctionResponsePayloadImpl.of(bidResponse);
final List<Audience> targeting = singletonList(new Audience(
"provider",
List.of(new AudienceId("audienceId"), new AudienceId("audienceId2")),
null,
1));
final BidResponseEnricher enricher = BidResponseEnricher.of(targeting, mapper, jsonMerger);

// when
final AuctionResponsePayload result = enricher.apply(auctionResponsePayload);

// then
assertThat(result.bidResponse()).isEqualTo(bidResponse);
}

@Test
public void shouldEnrichBidResponseByTargetingKeywords() {
// given
Expand Down
Loading
Loading