diff --git a/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Logging.kt b/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Logging.kt
index b7a9aef..2fb382b 100644
--- a/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Logging.kt
+++ b/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Logging.kt
@@ -2,6 +2,7 @@ package net.woggioni.gbcs.base
import org.slf4j.Logger
import org.slf4j.LoggerFactory
+import org.slf4j.event.Level
import java.nio.file.Files
import java.nio.file.Path
import java.util.logging.LogManager
@@ -52,6 +53,12 @@ inline fun log(log : Logger,
}
}
+inline fun Logger.log(level : Level, messageBuilder : () -> String) {
+ if(isEnabledForLevel(level)) {
+ makeLoggingEventBuilder(level).log(messageBuilder())
+ }
+}
+
inline fun Logger.trace(messageBuilder : () -> String) {
if(isTraceEnabled) {
trace(messageBuilder())
diff --git a/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Xml.kt b/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Xml.kt
index 6e61248..e4dcc39 100644
--- a/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Xml.kt
+++ b/gbcs-base/src/main/kotlin/net/woggioni/gbcs/base/Xml.kt
@@ -1,6 +1,7 @@
package net.woggioni.gbcs.base
import org.slf4j.LoggerFactory
+import org.slf4j.event.Level
import org.w3c.dom.Document
import org.w3c.dom.Element
import org.w3c.dom.Node
@@ -80,28 +81,17 @@ class Xml(val doc: Document, val element: Element) {
private val log = LoggerFactory.getLogger(ErrorHandler::class.java)
}
- override fun warning(ex: SAXParseException) {
- log.warn(
- "Problem at {}:{}:{} parsing deployment configuration: {}",
- fileURL, ex.lineNumber, ex.columnNumber, ex.message
- )
- }
+ override fun warning(ex: SAXParseException)= err(ex, Level.WARN)
- override fun error(ex: SAXParseException) {
- log.error(
- "Problem at {}:{}:{} parsing deployment configuration: {}",
- fileURL, ex.lineNumber, ex.columnNumber, ex.message
- )
+ private fun err(ex: SAXParseException, level: Level) {
+ log.log(level) {
+ "Problem at ${fileURL}:${ex.lineNumber}:${ex.columnNumber} parsing deployment configuration: ${ex.message}"
+ }
throw ex
}
- override fun fatalError(ex: SAXParseException) {
- log.error(
- "Problem at {}:{}:{} parsing deployment configuration: {}",
- fileURL, ex.lineNumber, ex.columnNumber, ex.message
- )
- throw ex
- }
+ override fun error(ex: SAXParseException) = err(ex, Level.ERROR)
+ override fun fatalError(ex: SAXParseException) = err(ex, Level.ERROR)
}
companion object {
diff --git a/gbcs-cli/src/main/java/module-info.java b/gbcs-cli/src/main/java/module-info.java
index 51539bd..e97ded5 100644
--- a/gbcs-cli/src/main/java/module-info.java
+++ b/gbcs-cli/src/main/java/module-info.java
@@ -6,6 +6,7 @@ module net.woggioni.gbcs.cli {
requires net.woggioni.gbcs.client;
requires kotlin.stdlib;
requires net.woggioni.jwo;
+ requires net.woggioni.gbcs.api;
exports net.woggioni.gbcs.cli.impl.converters to info.picocli;
opens net.woggioni.gbcs.cli.impl.commands to info.picocli;
diff --git a/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/ServerCommand.kt b/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/ServerCommand.kt
index ac5d878..5662960 100644
--- a/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/ServerCommand.kt
+++ b/gbcs-cli/src/main/kotlin/net/woggioni/gbcs/cli/impl/commands/ServerCommand.kt
@@ -2,11 +2,11 @@ package net.woggioni.gbcs.cli.impl.commands
import net.woggioni.gbcs.GradleBuildCacheServer
import net.woggioni.gbcs.GradleBuildCacheServer.Companion.DEFAULT_CONFIGURATION_URL
+import net.woggioni.gbcs.api.Configuration
import net.woggioni.gbcs.base.contextLogger
import net.woggioni.gbcs.base.debug
import net.woggioni.gbcs.base.info
import net.woggioni.gbcs.cli.impl.GbcsCommand
-import net.woggioni.gbcs.client.GbcsClient
import net.woggioni.jwo.Application
import net.woggioni.jwo.JWO
import picocli.CommandLine
@@ -42,8 +42,8 @@ class ServerCommand(app : Application) : GbcsCommand() {
)
private var configurationFile: Path = findConfigurationFile(app, "gbcs-server.xml")
- val configuration : GbcsClient.Configuration by lazy {
- GbcsClient.Configuration.parse(configurationFile)
+ val configuration : Configuration by lazy {
+ GradleBuildCacheServer.loadConfiguration(configurationFile)
}
override fun run() {
diff --git a/gbcs-cli/src/main/resources/net/woggioni/gbcs/cli/logback.xml b/gbcs-cli/src/main/resources/net/woggioni/gbcs/cli/logback.xml
index 217d42e..b3e8682 100644
--- a/gbcs-cli/src/main/resources/net/woggioni/gbcs/cli/logback.xml
+++ b/gbcs-cli/src/main/resources/net/woggioni/gbcs/cli/logback.xml
@@ -15,8 +15,6 @@
-
-
\ No newline at end of file
diff --git a/gbcs-client/src/jmh/java/net/woggioni/gbcs/benchmark/Main.java b/gbcs-client/src/jmh/java/net/woggioni/gbcs/benchmark/Main.java
deleted file mode 100644
index ee58d3c..0000000
--- a/gbcs-client/src/jmh/java/net/woggioni/gbcs/benchmark/Main.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package net.woggioni.gbcs.benchmark;
-
-import lombok.Getter;
-import lombok.SneakyThrows;
-import net.woggioni.jwo.Fun;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.annotations.BenchmarkMode;
-import org.openjdk.jmh.annotations.Level;
-import org.openjdk.jmh.annotations.Mode;
-import org.openjdk.jmh.annotations.OutputTimeUnit;
-import org.openjdk.jmh.annotations.Scope;
-import org.openjdk.jmh.annotations.Setup;
-import org.openjdk.jmh.annotations.State;
-import org.openjdk.jmh.annotations.TearDown;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.KeyStore;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
-
-public class Main {
-
- @SneakyThrows
- private static Properties loadProperties() {
- Properties properties = new Properties();
- try (final var is = Main.class.getResourceAsStream("/benchmark.properties")) {
- properties.load(is);
- }
- return properties;
- }
-
- private static final Properties properties = loadProperties();
-
- @State(Scope.Thread)
- public static class ExecutionPlan {
- private final Random random = new Random(101325);
-
- @Getter
- private final HttpClient client = createHttpClient();
-
- private final Map entries = new HashMap<>();
-
-
- private HttpClient createHttpClient() {
- final var clientBuilder = HttpClient.newBuilder();
- getSslContext().ifPresent(clientBuilder::sslContext);
- return clientBuilder.build();
- }
-
- public final Map getEntries() {
- return Collections.unmodifiableMap(entries);
- }
-
- public Map.Entry newEntry() {
- final var keyBuffer = new byte[0x20];
- random.nextBytes(keyBuffer);
- final var key = Base64.getUrlEncoder().encodeToString(keyBuffer);
- final var value = new byte[0x1000];
- random.nextBytes(value);
- return Map.entry(key, value);
- }
-
- @SneakyThrows
- public HttpRequest.Builder newRequestBuilder(String key) {
- final var requestBuilder = HttpRequest.newBuilder()
- .uri(getServerURI().resolve(key));
- String user = getUser();
- if (user != null) {
- requestBuilder.header("Authorization", buildAuthorizationHeader(user, getPassword()));
- }
- return requestBuilder;
- }
-
- @SneakyThrows
- public URI getServerURI() {
- return new URI(properties.getProperty("gbcs.server.url"));
- }
-
- @SneakyThrows
- public Optional getClientTrustStorePassword() {
- return Optional.ofNullable(properties.getProperty("gbcs.client.ssl.truststore.password"))
- .filter(Predicate.not(String::isEmpty));
-
- }
-
- @SneakyThrows
- public Optional getClientTrustStore() {
- return Optional.ofNullable(properties.getProperty("gbcs.client.ssl.truststore.file"))
- .filter(Predicate.not(String::isEmpty))
- .map(Path::of)
- .map((Fun) keyStoreFile -> {
- final var keyStore = KeyStore.getInstance("PKCS12");
- try (final var is = Files.newInputStream(keyStoreFile)) {
- keyStore.load(is, getClientTrustStorePassword().map(String::toCharArray).orElse(null));
- }
- return keyStore;
- });
-
- }
-
- @SneakyThrows
- public Optional getClientKeyStore() {
- return Optional.ofNullable(properties.getProperty("gbcs.client.ssl.keystore.file"))
- .filter(Predicate.not(String::isEmpty))
- .map(Path::of)
- .map((Fun) keyStoreFile -> {
- final var keyStore = KeyStore.getInstance("PKCS12");
- try (final var is = Files.newInputStream(keyStoreFile)) {
- keyStore.load(is, getClientKeyStorePassword().map(String::toCharArray).orElse(null));
- }
- return keyStore;
- });
-
- }
-
- @SneakyThrows
- public Optional getClientKeyStorePassword() {
- return Optional.ofNullable(properties.getProperty("gbcs.client.ssl.keystore.password"))
- .filter(Predicate.not(String::isEmpty));
-
- }
-
- @SneakyThrows
- public Optional getClientKeyPassword() {
- return Optional.ofNullable(properties.getProperty("gbcs.client.ssl.key.password"))
- .filter(Predicate.not(String::isEmpty));
-
- }
-
- @SneakyThrows
- public String getUser() {
- return Optional.ofNullable(properties.getProperty("gbcs.server.username"))
- .filter(Predicate.not(String::isEmpty))
- .orElse(null);
-
- }
-
- @SneakyThrows
- public String getPassword() {
- return Optional.ofNullable(properties.getProperty("gbcs.server.password"))
- .filter(Predicate.not(String::isEmpty))
- .orElse(null);
- }
-
- private String buildAuthorizationHeader(String user, String password) {
- final var b64 = Base64.getEncoder().encode(String.format("%s:%s", user, password).getBytes(StandardCharsets.UTF_8));
- return "Basic " + new String(b64);
- }
-
- @SneakyThrows
- private Optional getSslContext() {
- return getClientKeyStore().map((Fun) clientKeyStore -> {
- final var kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(clientKeyStore, getClientKeyStorePassword().map(String::toCharArray).orElse(null));
-
-
- // Set up trust manager factory with the truststore
- final var trustManagers = getClientTrustStore().map((Fun) ts -> {
- final var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(ts);
- return tmf.getTrustManagers();
- }).orElse(new TrustManager[0]);
-
- // Create SSL context with the key and trust managers
- final var sslContext = SSLContext.getInstance("TLS");
- sslContext.init(kmf.getKeyManagers(), trustManagers, null);
- return sslContext;
- });
- }
-
- @SneakyThrows
- @Setup(Level.Trial)
- public void setUp() {
- final var client = getClient();
- for (int i = 0; i < 1000; i++) {
- final var pair = newEntry();
- final var requestBuilder = newRequestBuilder(pair.getKey())
- .header("Content-Type", "application/octet-stream")
- .PUT(HttpRequest.BodyPublishers.ofByteArray(pair.getValue()));
- final var response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString());
- if (201 != response.statusCode()) {
- throw new IllegalStateException(Integer.toString(response.statusCode()));
- } else {
- entries.put(pair.getKey(), pair.getValue());
- }
- }
- }
-
- @TearDown
- public void tearDown() {
- client.close();
- }
-
-
- private Iterator> it = null;
-
- private Map.Entry nextEntry() {
- if (it == null || !it.hasNext()) {
- it = getEntries().entrySet().iterator();
- }
- return it.next();
- }
- }
-
- @SneakyThrows
- @Benchmark
- @BenchmarkMode(Mode.Throughput)
- @OutputTimeUnit(TimeUnit.SECONDS)
- public void get(ExecutionPlan plan) {
- final var client = plan.getClient();
- final var entry = plan.nextEntry();
- final var requestBuilder = plan.newRequestBuilder(entry.getKey())
- .header("Accept", "application/octet-stream")
- .GET();
- final var response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
- if (200 != response.statusCode()) {
- throw new IllegalStateException(Integer.toString(response.statusCode()));
- } else {
- if (!Arrays.equals(entry.getValue(), response.body())) {
- throw new IllegalStateException("Retrieved unexpected value");
- }
- }
- }
-
-
- @SneakyThrows
- @Benchmark
- @BenchmarkMode(Mode.Throughput)
- @OutputTimeUnit(TimeUnit.SECONDS)
- public void put(Main.ExecutionPlan plan) {
- final var client = plan.getClient();
- final var entry = plan.nextEntry();
-
- final var requestBuilder = plan.newRequestBuilder(entry.getKey())
- .header("Content-Type", "application/octet-stream")
- .PUT(HttpRequest.BodyPublishers.ofByteArray(entry.getValue()));
-
- final var response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofByteArray());
- if (201 != response.statusCode()) {
- throw new IllegalStateException(Integer.toString(response.statusCode()));
- }
- }
-}
diff --git a/gbcs-client/src/jmh/resources/benchmark.properties b/gbcs-client/src/jmh/resources/benchmark.properties
deleted file mode 100644
index aa7d29e..0000000
--- a/gbcs-client/src/jmh/resources/benchmark.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-gbcs.server.url= https://gbcs.woggioni.net:443
-gbcs.client.ssl.keystore.file=conf/woggioni@c962475fa38.p12
-gbcs.client.ssl.keystore.password=password
-gbcs.client.ssl.key.password=password
-gbcs.client.ssl.truststore.file=conf/truststore.pfx
-gbcs.client.ssl.truststore.password=password
\ No newline at end of file
diff --git a/src/main/kotlin/net/woggioni/gbcs/GradleBuildCacheServer.kt b/src/main/kotlin/net/woggioni/gbcs/GradleBuildCacheServer.kt
index bd4b92d..533d674 100644
--- a/src/main/kotlin/net/woggioni/gbcs/GradleBuildCacheServer.kt
+++ b/src/main/kotlin/net/woggioni/gbcs/GradleBuildCacheServer.kt
@@ -507,9 +507,9 @@ class GradleBuildCacheServer(private val cfg: Configuration) {
val DEFAULT_CONFIGURATION_URL by lazy { "classpath:net/woggioni/gbcs/gbcs-default.xml".toUrl() }
fun loadConfiguration(configurationFile: Path): Configuration {
- val dbf = Xml.newDocumentBuilderFactory(null)
- val db = dbf.newDocumentBuilder()
- val doc = Files.newInputStream(configurationFile).use(db::parse)
+ val doc = Files.newInputStream(configurationFile).use {
+ Xml.parseXml(configurationFile.toUri().toURL(), it)
+ }
return Parser.parse(doc)
}
diff --git a/src/main/kotlin/net/woggioni/gbcs/configuration/Parser.kt b/src/main/kotlin/net/woggioni/gbcs/configuration/Parser.kt
index 10f886e..d969838 100644
--- a/src/main/kotlin/net/woggioni/gbcs/configuration/Parser.kt
+++ b/src/main/kotlin/net/woggioni/gbcs/configuration/Parser.kt
@@ -19,7 +19,6 @@ import org.w3c.dom.TypeInfo
import java.nio.file.Paths
object Parser {
-
fun parse(document: Document): Configuration {
val root = document.documentElement
val anonymousUser = User("", null, emptySet())