feat: ResolvedContainerConfig record and three-layer ConfigMerger

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-08 20:18:25 +02:00
parent fef0239b1d
commit b7d00548c5
2 changed files with 125 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
package com.cameleer3.server.core.runtime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class ConfigMerger {
private ConfigMerger() {}
public static ResolvedContainerConfig resolve(
GlobalRuntimeDefaults global,
Map<String, Object> envConfig,
Map<String, Object> appConfig) {
return new ResolvedContainerConfig(
intVal(appConfig, envConfig, "memoryLimitMb", global.memoryLimitMb()),
intOrNull(appConfig, envConfig, "memoryReserveMb"),
intVal(appConfig, envConfig, "cpuShares", global.cpuShares()),
doubleOrNull(appConfig, envConfig, "cpuLimit"),
intVal(appConfig, envConfig, "appPort", 8080),
intList(appConfig, envConfig, "exposedPorts"),
stringMap(appConfig, envConfig, "customEnvVars"),
boolVal(appConfig, envConfig, "stripPathPrefix", true),
boolVal(appConfig, envConfig, "sslOffloading", true),
stringVal(appConfig, envConfig, "routingMode", global.routingMode()),
stringVal(appConfig, envConfig, "routingDomain", global.routingDomain()),
stringVal(appConfig, envConfig, "serverUrl", global.serverUrl()),
intVal(appConfig, envConfig, "replicas", 1),
stringVal(appConfig, envConfig, "deploymentStrategy", "blue-green")
);
}
private static int intVal(Map<String, Object> app, Map<String, Object> env, String key, int fallback) {
if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue();
if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue();
return fallback;
}
private static Integer intOrNull(Map<String, Object> app, Map<String, Object> env, String key) {
if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue();
if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue();
return null;
}
private static Double doubleOrNull(Map<String, Object> app, Map<String, Object> env, String key) {
if (app.containsKey(key) && app.get(key) instanceof Number n) return n.doubleValue();
if (env.containsKey(key) && env.get(key) instanceof Number n) return n.doubleValue();
return null;
}
private static boolean boolVal(Map<String, Object> app, Map<String, Object> env, String key, boolean fallback) {
if (app.containsKey(key) && app.get(key) instanceof Boolean b) return b;
if (env.containsKey(key) && env.get(key) instanceof Boolean b) return b;
return fallback;
}
private static String stringVal(Map<String, Object> app, Map<String, Object> env, String key, String fallback) {
if (app.containsKey(key) && app.get(key) instanceof String s) return s;
if (env.containsKey(key) && env.get(key) instanceof String s) return s;
return fallback;
}
@SuppressWarnings("unchecked")
private static List<Integer> intList(Map<String, Object> app, Map<String, Object> env, String key) {
Object val = app.containsKey(key) ? app.get(key) : env.get(key);
if (val instanceof List<?> list) {
return list.stream()
.filter(Number.class::isInstance)
.map(n -> ((Number) n).intValue())
.toList();
}
return List.of();
}
@SuppressWarnings("unchecked")
private static Map<String, String> stringMap(Map<String, Object> app, Map<String, Object> env, String key) {
Object val = app.containsKey(key) ? app.get(key) : env.get(key);
if (val instanceof Map<?, ?> map) {
Map<String, String> result = new HashMap<>();
map.forEach((k, v) -> result.put(String.valueOf(k), String.valueOf(v)));
return Collections.unmodifiableMap(result);
}
return Map.of();
}
/** Global defaults extracted from application.yml @Value fields */
public record GlobalRuntimeDefaults(
int memoryLimitMb,
int cpuShares,
String routingMode,
String routingDomain,
String serverUrl
) {}
}

View File

@@ -0,0 +1,29 @@
package com.cameleer3.server.core.runtime;
import java.util.List;
import java.util.Map;
public record ResolvedContainerConfig(
int memoryLimitMb,
Integer memoryReserveMb,
int cpuShares,
Double cpuLimit,
int appPort,
List<Integer> exposedPorts,
Map<String, String> customEnvVars,
boolean stripPathPrefix,
boolean sslOffloading,
String routingMode,
String routingDomain,
String serverUrl,
int replicas,
String deploymentStrategy
) {
public long memoryLimitBytes() {
return (long) memoryLimitMb * 1024 * 1024;
}
public Long memoryReserveBytes() {
return memoryReserveMb != null ? (long) memoryReserveMb * 1024 * 1024 : null;
}
}