Skip to content

Commit 8aa7fdc

Browse files
committed
Refactor: separated disk related functionality of VendorListService
1 parent e2f8349 commit 8aa7fdc

8 files changed

Lines changed: 843 additions & 338 deletions

File tree

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package org.prebid.server.privacy.gdpr.vendorlist;
2+
3+
import com.github.benmanes.caffeine.cache.Caffeine;
4+
import io.vertx.core.Future;
5+
import io.vertx.core.Promise;
6+
import io.vertx.core.buffer.Buffer;
7+
import io.vertx.core.file.FileProps;
8+
import io.vertx.core.file.FileSystem;
9+
import io.vertx.core.file.FileSystemException;
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.apache.commons.lang3.exception.ExceptionUtils;
12+
import org.prebid.server.exception.PreBidException;
13+
import org.prebid.server.json.JacksonMapper;
14+
import org.prebid.server.log.ConditionalLogger;
15+
import org.prebid.server.log.Logger;
16+
import org.prebid.server.log.LoggerFactory;
17+
import org.prebid.server.privacy.gdpr.vendorlist.proto.Vendor;
18+
import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorList;
19+
20+
import java.io.File;
21+
import java.nio.file.Files;
22+
import java.nio.file.Paths;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
import java.util.stream.Collectors;
26+
27+
public class VendorListFileStore {
28+
29+
private static final Logger logger = LoggerFactory.getLogger(VendorListFileStore.class);
30+
private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger);
31+
32+
private static final String JSON_SUFFIX = ".json";
33+
34+
private final double logSamplingRate;
35+
private final FileSystem fileSystem;
36+
private final JacksonMapper mapper;
37+
38+
public VendorListFileStore(double logSamplingRate,
39+
FileSystem fileSystem,
40+
JacksonMapper mapper) {
41+
42+
this.logSamplingRate = logSamplingRate;
43+
this.fileSystem = Objects.requireNonNull(fileSystem);
44+
this.mapper = Objects.requireNonNull(mapper);
45+
}
46+
47+
Map<Integer, Map<Integer, Vendor>> createCacheFromDisk(String cacheDir) {
48+
createAndCheckWritePermissionsForCacheDir(cacheDir);
49+
final Map<String, String> versionToFileContent = readFileSystemCache(cacheDir);
50+
51+
final Map<Integer, Map<Integer, Vendor>> cache = Caffeine.newBuilder()
52+
.<Integer, Map<Integer, Vendor>>build()
53+
.asMap();
54+
55+
for (Map.Entry<String, String> versionAndFileContent : versionToFileContent.entrySet()) {
56+
final VendorList vendorList = VendorListUtil.parseVendorList(versionAndFileContent.getValue(), mapper);
57+
58+
cache.put(Integer.valueOf(versionAndFileContent.getKey()), vendorList.getVendors());
59+
}
60+
return cache;
61+
}
62+
63+
private void createAndCheckWritePermissionsForCacheDir(String cacheDir) {
64+
final FileProps props = fileSystem.existsBlocking(cacheDir) ? fileSystem.propsBlocking(cacheDir) : null;
65+
if (props == null || !props.isDirectory()) {
66+
try {
67+
fileSystem.mkdirsBlocking(cacheDir);
68+
} catch (FileSystemException e) {
69+
throw new PreBidException("Cannot create directory: " + cacheDir, e);
70+
}
71+
} else if (!Files.isWritable(Paths.get(cacheDir))) {
72+
throw new PreBidException("No write permissions for directory: " + cacheDir);
73+
}
74+
}
75+
76+
private Map<String, String> readFileSystemCache(String cacheDir) {
77+
return fileSystem.readDirBlocking(cacheDir).stream()
78+
.filter(filepath -> filepath.endsWith(JSON_SUFFIX))
79+
.collect(Collectors.toMap(filepath -> StringUtils.removeEnd(new File(filepath).getName(), JSON_SUFFIX),
80+
filename -> fileSystem.readFileBlocking(filename).toString()));
81+
}
82+
83+
Future<VendorListResult> saveToFile(VendorListResult vendorListResult, String cacheDir, String generationVersion) {
84+
final Promise<VendorListResult> promise = Promise.promise();
85+
final int version = vendorListResult.getVersion();
86+
final String filepath = new File(cacheDir, version + JSON_SUFFIX).getPath();
87+
88+
fileSystem.writeFile(filepath, Buffer.buffer(vendorListResult.getVendorListAsString()), result -> {
89+
if (result.succeeded()) {
90+
promise.complete(vendorListResult);
91+
} else {
92+
conditionalLogger.error(
93+
"Could not create new vendor list for version %s.%s, file: %s, trace: %s".formatted(
94+
generationVersion, version, filepath, ExceptionUtils.getStackTrace(result.cause())),
95+
logSamplingRate);
96+
promise.fail(result.cause());
97+
}
98+
});
99+
100+
return promise.future();
101+
}
102+
103+
Map<Integer, Vendor> readFallbackVendorList(String fallbackVendorListPath) {
104+
if (StringUtils.isBlank(fallbackVendorListPath)) {
105+
return null;
106+
}
107+
108+
final String vendorListContent = fileSystem.readFileBlocking(fallbackVendorListPath).toString();
109+
final VendorList vendorList = VendorListUtil.parseVendorList(vendorListContent, mapper);
110+
if (!VendorListUtil.vendorListIsValid(vendorList)) {
111+
throw new PreBidException("Fallback vendor list parsed but has invalid data: " + vendorListContent);
112+
}
113+
114+
return vendorList.getVendors();
115+
}
116+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.prebid.server.privacy.gdpr.vendorlist;
2+
3+
import lombok.Value;
4+
import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorList;
5+
6+
@Value(staticConstructor = "of")
7+
class VendorListResult {
8+
9+
int version;
10+
11+
String vendorListAsString;
12+
13+
VendorList vendorList;
14+
}

0 commit comments

Comments
 (0)