Skip to content

Commit 7799e04

Browse files
Added parsing and writing
1 parent 179bf0d commit 7799e04

6 files changed

Lines changed: 334 additions & 1 deletion

File tree

temporal-envconfig/src/main/java/io/temporal/envconfig/ClientConfig.java

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package io.temporal.envconfig;
22

33
import com.fasterxml.jackson.databind.ObjectReader;
4+
import com.fasterxml.jackson.databind.ObjectWriter;
45
import com.fasterxml.jackson.dataformat.toml.TomlMapper;
56
import io.temporal.common.Experimental;
67
import java.io.*;
78
import java.util.Map;
9+
import java.util.Objects;
810

911
/** ClientConfig represents a client config file. */
1012
@Experimental
@@ -51,7 +53,6 @@ public static ClientConfig load(LoadClientConfigOptions options) throws IOExcept
5153
reader.withoutFeatures(
5254
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
5355
}
54-
5556
if (options.getConfigFileData() != null && options.getConfigFileData().length > 0) {
5657
if (options.getConfigFilePath() != null && !options.getConfigFilePath().isEmpty()) {
5758
throw new IllegalArgumentException(
@@ -79,6 +80,56 @@ public static ClientConfig load(LoadClientConfigOptions options) throws IOExcept
7980
}
8081
}
8182

83+
/**
84+
* Load client config from given TOML data.
85+
*
86+
* @param tomlData TOML data to parse
87+
* @return the parsed client config
88+
* @throws IOException if the TOML data cannot be parsed
89+
*/
90+
public static ClientConfig fromToml(byte[] tomlData) throws IOException {
91+
return fromToml(tomlData, ClientConfigFromTomlOptions.getDefaultInstance());
92+
}
93+
94+
/**
95+
* Load client config from given TOML data.
96+
*
97+
* @param tomlData TOML data to parse
98+
* @param options options to control parsing the TOML data
99+
* @return the parsed client config
100+
* @throws IOException if the TOML data cannot be parsed
101+
*/
102+
public static ClientConfig fromToml(byte[] tomlData, ClientConfigFromTomlOptions options)
103+
throws IOException {
104+
ObjectReader reader = new TomlMapper().readerFor(ClientConfigToml.TomlClientConfig.class);
105+
if (options.isStrictConfigFile()) {
106+
reader =
107+
reader.withFeatures(
108+
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
109+
} else {
110+
reader =
111+
reader.withoutFeatures(
112+
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
113+
}
114+
ClientConfigToml.TomlClientConfig result = reader.readValue(tomlData);
115+
return new ClientConfig(ClientConfigToml.getClientProfiles(result));
116+
}
117+
118+
/**
119+
* Convert the client config to TOML data. Encoding is UTF-8.
120+
*
121+
* @param config the client config to convert
122+
* @return the TOML data as bytes
123+
* @apiNote The output will not be identical to the input if the config was loaded from a file
124+
* because comments and formatting are not preserved.
125+
*/
126+
public static byte[] toTomlAsBytes(ClientConfig config) throws IOException {
127+
ObjectWriter writer = new TomlMapper().writerFor(ClientConfigToml.TomlClientConfig.class);
128+
return writer.writeValueAsBytes(
129+
new ClientConfigToml.TomlClientConfig(
130+
ClientConfigToml.fromClientProfiles(config.getProfiles())));
131+
}
132+
82133
public ClientConfig(Map<String, ClientConfigProfile> profiles) {
83134
this.profiles = profiles;
84135
}
@@ -89,4 +140,21 @@ public ClientConfig(Map<String, ClientConfigProfile> profiles) {
89140
public Map<String, ClientConfigProfile> getProfiles() {
90141
return profiles;
91142
}
143+
144+
@Override
145+
public boolean equals(Object o) {
146+
if (o == null || getClass() != o.getClass()) return false;
147+
ClientConfig that = (ClientConfig) o;
148+
return Objects.equals(profiles, that.profiles);
149+
}
150+
151+
@Override
152+
public int hashCode() {
153+
return Objects.hashCode(profiles);
154+
}
155+
156+
@Override
157+
public String toString() {
158+
return "ClientConfig{" + "profiles=" + profiles + '}';
159+
}
92160
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package io.temporal.envconfig;
2+
3+
/**
4+
* Options for parsing a client config toml file in {@link ClientConfig#fromToml(byte[],
5+
* ClientConfigFromTomlOptions)}
6+
*/
7+
public class ClientConfigFromTomlOptions {
8+
/** Create a builder for {@link ClientConfigFromTomlOptions}. */
9+
public static Builder newBuilder() {
10+
return new ClientConfigFromTomlOptions.Builder();
11+
}
12+
13+
/** Create a builder from an existing {@link ClientConfigFromTomlOptions}. */
14+
public static Builder newBuilder(ClientConfigFromTomlOptions options) {
15+
return new Builder(options);
16+
}
17+
18+
/** Returns a default instance of {@link ClientConfigFromTomlOptions} with all fields unset. */
19+
public static ClientConfigFromTomlOptions getDefaultInstance() {
20+
return new ClientConfigFromTomlOptions.Builder().build();
21+
}
22+
23+
private final Boolean strictConfigFile;
24+
25+
private ClientConfigFromTomlOptions(Boolean strictConfigFile) {
26+
this.strictConfigFile = strictConfigFile;
27+
}
28+
29+
public Boolean isStrictConfigFile() {
30+
return strictConfigFile;
31+
}
32+
33+
public static class Builder {
34+
private Boolean strictConfigFile = false;
35+
36+
private Builder() {}
37+
38+
private Builder(ClientConfigFromTomlOptions options) {
39+
this.strictConfigFile = options.strictConfigFile;
40+
}
41+
42+
/**
43+
* When true, the parser will fail if the config file contains unknown fields. Default is false.
44+
*/
45+
public Boolean isStrictConfigFile() {
46+
return strictConfigFile;
47+
}
48+
49+
public ClientConfigFromTomlOptions build() {
50+
return new ClientConfigFromTomlOptions(strictConfigFile);
51+
}
52+
}
53+
}

temporal-envconfig/src/main/java/io/temporal/envconfig/ClientConfigProfile.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.nio.file.Files;
1313
import java.nio.file.Paths;
1414
import java.util.Map;
15+
import java.util.Objects;
1516

1617
/** ClientConfigProfile is profile-level configuration for a client. */
1718
@Experimental
@@ -356,6 +357,62 @@ public ClientConfigTLS getTls() {
356357
return tls;
357358
}
358359

360+
@Override
361+
public boolean equals(Object o) {
362+
if (o == null || getClass() != o.getClass()) return false;
363+
ClientConfigProfile profile = (ClientConfigProfile) o;
364+
// Compare metadata properly
365+
if (this.metadata == null) {
366+
if (profile.metadata != null && profile.metadata.keys() != null) {
367+
return false;
368+
}
369+
} else if (profile.metadata == null) {
370+
if (this.metadata.keys() != null) {
371+
return false;
372+
}
373+
} else {
374+
// Both non-null, compare keys and values
375+
if (!Objects.equals(this.metadata.keys(), profile.metadata.keys())) {
376+
return false;
377+
}
378+
for (String key : this.metadata.keys()) {
379+
if (!Objects.equals(
380+
this.metadata.get(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER)),
381+
profile.metadata.get(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER)))) {
382+
return false;
383+
}
384+
}
385+
}
386+
return Objects.equals(namespace, profile.namespace)
387+
&& Objects.equals(address, profile.address)
388+
&& Objects.equals(apiKey, profile.apiKey)
389+
&& Objects.equals(tls, profile.tls);
390+
}
391+
392+
@Override
393+
public int hashCode() {
394+
return Objects.hash(namespace, address, apiKey, metadata, tls);
395+
}
396+
397+
@Override
398+
public String toString() {
399+
return "ClientConfigProfile{"
400+
+ "namespace='"
401+
+ namespace
402+
+ '\''
403+
+ ", address='"
404+
+ address
405+
+ '\''
406+
+ ", apiKey='"
407+
+ apiKey
408+
+ '\''
409+
+ ", metadata="
410+
+ metadata
411+
+ ", tls="
412+
+ tls
413+
+ '}';
414+
}
415+
359416
public static final class Builder {
360417
private String namespace;
361418
private String address;

temporal-envconfig/src/main/java/io/temporal/envconfig/ClientConfigTLS.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.temporal.envconfig;
22

33
import io.temporal.common.Experimental;
4+
import java.util.Arrays;
5+
import java.util.Objects;
46

57
/** TLS configuration for a client. */
68
@Experimental
@@ -91,6 +93,63 @@ public Builder toBuilder() {
9193
return new Builder(this);
9294
}
9395

96+
@Override
97+
public boolean equals(Object o) {
98+
if (o == null || getClass() != o.getClass()) return false;
99+
ClientConfigTLS that = (ClientConfigTLS) o;
100+
return Objects.equals(disabled, that.disabled)
101+
&& Objects.equals(clientCertPath, that.clientCertPath)
102+
&& Objects.deepEquals(clientCertData, that.clientCertData)
103+
&& Objects.equals(clientKeyPath, that.clientKeyPath)
104+
&& Objects.deepEquals(clientKeyData, that.clientKeyData)
105+
&& Objects.equals(serverCACertPath, that.serverCACertPath)
106+
&& Objects.deepEquals(serverCACertData, that.serverCACertData)
107+
&& Objects.equals(serverName, that.serverName)
108+
&& Objects.equals(disableHostVerification, that.disableHostVerification);
109+
}
110+
111+
@Override
112+
public int hashCode() {
113+
return Objects.hash(
114+
disabled,
115+
clientCertPath,
116+
Arrays.hashCode(clientCertData),
117+
clientKeyPath,
118+
Arrays.hashCode(clientKeyData),
119+
serverCACertPath,
120+
Arrays.hashCode(serverCACertData),
121+
serverName,
122+
disableHostVerification);
123+
}
124+
125+
@Override
126+
public String toString() {
127+
return "ClientConfigTLS{"
128+
+ "disabled="
129+
+ disabled
130+
+ ", clientCertPath='"
131+
+ clientCertPath
132+
+ '\''
133+
+ ", clientCertData="
134+
+ Arrays.toString(clientCertData)
135+
+ ", clientKeyPath='"
136+
+ clientKeyPath
137+
+ '\''
138+
+ ", clientKeyData="
139+
+ Arrays.toString(clientKeyData)
140+
+ ", serverCACertPath='"
141+
+ serverCACertPath
142+
+ '\''
143+
+ ", serverCACertData="
144+
+ Arrays.toString(serverCACertData)
145+
+ ", serverName='"
146+
+ serverName
147+
+ '\''
148+
+ ", disableHostVerification="
149+
+ disableHostVerification
150+
+ '}';
151+
}
152+
94153
public static class Builder {
95154
private String clientCertPath;
96155
private byte[] clientCertData;

temporal-envconfig/src/main/java/io/temporal/envconfig/ClientConfigToml.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,51 @@ static Map<String, ClientConfigProfile> getClientProfiles(
180180
}
181181
return profiles;
182182
}
183+
184+
public static Map<String, TomlClientConfigProfile> fromClientProfiles(
185+
Map<String, ClientConfigProfile> profiles) {
186+
Map<String, TomlClientConfigProfile> tomlProfiles = new HashMap<>(profiles.size());
187+
for (Map.Entry<String, ClientConfigProfile> entry : profiles.entrySet()) {
188+
String profileName = entry.getKey();
189+
ClientConfigProfile profile = entry.getValue();
190+
TomlClientConfigTLS tls = null;
191+
if (profile.getTls() != null) {
192+
tls =
193+
new TomlClientConfigTLS(
194+
profile.getTls().isDisabled(),
195+
profile.getTls().getClientCertPath(),
196+
profile.getTls().getClientCertData() != null
197+
? new String(profile.getTls().getClientCertData(), StandardCharsets.UTF_8)
198+
: null,
199+
profile.getTls().getClientKeyPath(),
200+
profile.getTls().getClientKeyData() != null
201+
? new String(profile.getTls().getClientKeyData(), StandardCharsets.UTF_8)
202+
: null,
203+
profile.getTls().getServerCACertPath(),
204+
profile.getTls().getServerCACertData() != null
205+
? new String(profile.getTls().getServerCACertData(), StandardCharsets.UTF_8)
206+
: null,
207+
profile.getTls().getServerName(),
208+
profile.getTls().isDisableHostVerification());
209+
}
210+
Map<String, String> grpcMeta = null;
211+
if (profile.getMetadata() != null) {
212+
grpcMeta = new HashMap<>();
213+
for (String key : profile.getMetadata().keys()) {
214+
Metadata.Key<String> metaKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
215+
Iterable<String> values = profile.getMetadata().getAll(metaKey);
216+
if (values != null) {
217+
// Join multiple values with comma
218+
String joinedValues = String.join(",", values);
219+
grpcMeta.put(key, joinedValues);
220+
}
221+
}
222+
}
223+
TomlClientConfigProfile tomlProfile =
224+
new TomlClientConfigProfile(
225+
profile.getAddress(), profile.getNamespace(), profile.getApiKey(), tls, grpcMeta);
226+
tomlProfiles.put(profileName, tomlProfile);
227+
}
228+
return tomlProfiles;
229+
}
183230
}

0 commit comments

Comments
 (0)