Skip to content

Commit bb6dae4

Browse files
committed
Abstracted config loading for JTPClient and JTPServer
1 parent db95939 commit bb6dae4

File tree

7 files changed

+452
-260
lines changed

7 files changed

+452
-260
lines changed

.github/workflows/javadoc.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Java Build and Javadoc Generation
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
build:
9+
if: startsWith(github.ref, 'refs/heads/main') || startsWith(github.ref, 'refs/heads/development-')
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
16+
- name: Set up JDK 21
17+
uses: actions/setup-java@v4
18+
with:
19+
distribution: 'temurin'
20+
java-version: '21'
21+
22+
- name: Grant execute permission for Gradle wrapper
23+
run: chmod +x gradlew
24+
25+
- name: Generate Javadoc
26+
run: ./gradlew allJavadoc
27+
28+
- name: Upload Javadoc
29+
uses: actions/upload-artifact@v3
30+
with:
31+
name: javadoc
32+
path: build/docs/javadoc

build.gradle

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ subprojects {
2121
}
2222

2323
dependencies {
24-
implementation("org.reujdon.async:Java-Async:1.0.0")
25-
2624
implementation 'org.slf4j:slf4j-api:2.0.17'
2725
implementation 'ch.qos.logback:logback-classic:1.4.7'
2826
implementation 'com.google.code.gson:gson:2.8.8'
@@ -38,19 +36,13 @@ subprojects {
3836
}
3937
}
4038

41-
tasks.register('aggregateJavadoc', Javadoc) {
42-
description = 'Generates unified Javadoc from all subprojects'
43-
group = 'Documentation'
44-
45-
def allJavaSources = files(subprojects.collect { it.sourceSets.main.allJava })
46-
def allClasspaths = files(subprojects.collect { it.sourceSets.main.compileClasspath })
47-
48-
source.setFrom(allJavaSources)
49-
classpath.setFrom(allClasspaths)
50-
51-
destinationDir = layout.buildDirectory.dir("docs/javadoc").get().asFile
39+
tasks.register('allJavadoc', Javadoc) {
40+
source subprojects.collect { it.sourceSets.main.allJava }
41+
classpath = files(subprojects.collect { it.configurations.compileClasspath })
42+
destinationDir = file("${projectDir}/javadoc")
43+
title = "${project.name} Javadoc"
5244
}
5345

5446
tasks.named("build") {
55-
dependsOn("aggregateJavadoc")
47+
dependsOn("allJavadoc")
5648
}

client/src/main/java/org/reujdon/jtp/client/JTPClient.java

Lines changed: 12 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.reujdon.jtp.client;
22

33
import org.reujdon.jtp.client.commands.Command;
4-
import org.reujdon.jtp.shared.PropertiesUtil;
54
import org.reujdon.jtp.shared.json.JsonException;
65
import org.reujdon.jtp.shared.messaging.Message;
76
import org.reujdon.jtp.shared.messaging.MessageFactory;
@@ -36,20 +35,7 @@
3635
public class JTPClient implements Runnable, AutoCloseable {
3736
private static final Logger logger = LoggerFactory.getLogger(JTPClient.class);
3837

39-
// TODO: abstract config logic to be reused in server
40-
// Constants for environment variable keys
41-
private static final String ENV_HOST = "CLIENT_HOST";
42-
private static final String ENV_PORT = "CLIENT_PORT";
43-
private static final String ENV_TRUSTSTORE_PATH = "CLIENT_TRUSTSTORE_PATH";
44-
private static final String ENV_TRUSTSTORE_PASSWORD = "CLIENT_TRUSTSTORE_PASSWORD";
45-
private static final String ENV_API_KEY = "CLIENT_API_KEY";
46-
private static final String DEFAULT_CONFIG_FILE = "client.properties";
47-
48-
private String host;
49-
private int port = -1;
50-
private String apiKey;
51-
private String truststorePath;
52-
private String truststorePassword;
38+
private final JTPClientConfig config;
5339

5440
private SSLSocket sslSocket;
5541

@@ -82,112 +68,8 @@ public class JTPClient implements Runnable, AutoCloseable {
8268
* @see #JTPClient()
8369
*/
8470
public JTPClient(String configFile) {
85-
loadConfig(configFile);
86-
}
87-
88-
/**
89-
* Loads configuration from environment and properties file.
90-
*
91-
* @param configFile path to properties file
92-
* @see #loadFromEnvVars()
93-
* @see #loadFromPropertiesFile(String)
94-
*/
95-
private void loadConfig(String configFile){
96-
loadFromEnvVars();
97-
98-
if (hasMissingConfig()) {
99-
if (configFile == null)
100-
configFile = DEFAULT_CONFIG_FILE;
101-
102-
loadFromPropertiesFile(configFile);
103-
}
104-
105-
validateConfig();
106-
}
107-
108-
/**
109-
* Checks for missing required configuration.
110-
*
111-
* @return true if any required config is missing
112-
*/
113-
private boolean hasMissingConfig() {
114-
return host == null || port == -1 || apiKey == null || truststorePath == null || truststorePassword == null;
115-
}
116-
117-
/**
118-
* Loads configuration from environment variables.
119-
*/
120-
private void loadFromEnvVars() {
121-
String envHost = System.getenv(ENV_HOST);
122-
if (envHost != null && !envHost.isBlank())
123-
this.host = envHost.trim();
124-
125-
String envApiKey = System.getenv(ENV_API_KEY);
126-
if (envApiKey != null && !envApiKey.isBlank())
127-
this.apiKey = envApiKey.trim();
128-
129-
String envPort = System.getenv(ENV_PORT);
130-
if (envPort != null) {
131-
try {
132-
this.port = Integer.parseInt(envPort);
133-
} catch (NumberFormatException e) {
134-
throw new IllegalArgumentException("Invalid PORT in env vars", e);
135-
}
136-
}
137-
138-
String envTruststorePath = System.getenv(ENV_TRUSTSTORE_PATH);
139-
if (envTruststorePath != null)
140-
this.truststorePath = envTruststorePath;
141-
142-
String envTruststorePassword = System.getenv(ENV_TRUSTSTORE_PASSWORD);
143-
if (envTruststorePassword != null)
144-
this.truststorePassword = envTruststorePassword;
145-
}
146-
147-
/**
148-
* Loads configuration from properties file.
149-
*
150-
* @param configFile path to properties file
151-
* @throws IllegalArgumentException if file is invalid
152-
*/
153-
private void loadFromPropertiesFile(String configFile) {
154-
if (this.host == null)
155-
this.host = PropertiesUtil.getString(configFile, "client.host");
156-
157-
if (this.port == -1)
158-
this.port = PropertiesUtil.getInteger(configFile, "client.port");
159-
160-
if (this.apiKey == null)
161-
this.apiKey = PropertiesUtil.getString(configFile, "client.apiKey");
162-
163-
if (this.truststorePath == null)
164-
this.truststorePath = PropertiesUtil.getString(configFile, "client.path");
165-
166-
if (this.truststorePassword == null)
167-
this.truststorePassword = PropertiesUtil.getString(configFile, "client.password");
168-
169-
}
170-
171-
/**
172-
* Validates loaded configuration.
173-
*
174-
* @throws IllegalArgumentException if any config is invalid
175-
*/
176-
private void validateConfig() {
177-
if (this.host == null || this.host.isBlank())
178-
throw new IllegalArgumentException("Host must be set via " + ENV_HOST + " or properties file");
179-
180-
if (this.port < 0 || this.port > 65536)
181-
throw new IllegalArgumentException("PORT must be between 0 and 65536 and set via " + ENV_PORT + " or properties file");
182-
183-
if (this.apiKey == null || this.apiKey.isBlank())
184-
throw new IllegalArgumentException("API key must be set via " + ENV_API_KEY + " or properties file");
185-
186-
if (this.truststorePath == null || this.truststorePath.isBlank())
187-
logger.warn("Truststore path not set");
188-
189-
if (this.truststorePath != null && this.truststorePassword == null)
190-
throw new IllegalArgumentException("Truststore password must be set via " + ENV_TRUSTSTORE_PASSWORD + " or properties file");
71+
this.config = new JTPClientConfig();
72+
config.loadConfig(configFile, "client.properties");
19173
}
19274

19375
/**
@@ -201,14 +83,14 @@ public void run() {
20183
try{
20284
SSLContext sslContext = createSSLContext();
20385
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
204-
sslSocket = (SSLSocket) sslSocketFactory.createSocket(host, port);
86+
sslSocket = (SSLSocket) sslSocketFactory.createSocket(config.host, config.port);
20587

20688
sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
20789

20890
in = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
20991
out = new PrintWriter(sslSocket.getOutputStream(), true);
21092

211-
logger.info("Connected to server at {} : {}\n", host, port);
93+
logger.info("Connected to server at {} : {}\n", config.host, config.port);
21294

21395
running = true;
21496

@@ -238,19 +120,19 @@ public void run() {
238120
*/
239121
private SSLContext createSSLContext() {
240122
try {
241-
if (truststorePath == null || truststorePath.trim().isEmpty()) {
123+
if (config.truststorePath == null || config.truststorePath.isBlank()) {
242124
logger.warn("No truststore configured - using default SSLContext with standard certificate validation");
243125
return SSLContext.getDefault();
244126
}
245127

246-
File truststoreFile = new File(truststorePath);
128+
File truststoreFile = new File(config.truststorePath);
247129
if (!truststoreFile.exists())
248-
throw new FileNotFoundException("Truststore file not found at: " + truststorePath);
130+
throw new FileNotFoundException("Truststore file not found at: " + config.truststorePath);
249131

250-
try (FileInputStream fis = new FileInputStream(truststorePath)) {
132+
try (FileInputStream fis = new FileInputStream(config.truststorePath)) {
251133
// Load the truststore
252134
KeyStore trustStore = KeyStore.getInstance("JKS");
253-
trustStore.load(fis, truststorePassword.toCharArray());
135+
trustStore.load(fis, config.truststorePassword.toCharArray());
254136

255137
// Initialize trust manager factory
256138
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
@@ -273,7 +155,7 @@ private SSLContext createSSLContext() {
273155
private void sendAuth() {
274156
logger.info("Client authenticating...");
275157

276-
Auth auth = new Auth(apiKey);
158+
Auth auth = new Auth(config.apiKey);
277159
out.println(auth.toJSON());
278160
out.flush();
279161
}
@@ -399,7 +281,7 @@ public void close() {
399281
private void waitForPendingCommands() {
400282
logger.info("Waiting for pending responses to complete...");
401283

402-
final int maxWaitMs = 5000;
284+
final int maxWaitMs = config.shutdownTimeout;
403285
final int checkIntervalMs = 100;
404286
final long endTime = System.currentTimeMillis() + maxWaitMs;
405287

0 commit comments

Comments
 (0)