Skip to content

Commit 49c041e

Browse files
authored
Rework CryptDataConverter example to use new PayloadCodec (temporalio#340)
1 parent c0a7bd3 commit 49c041e

File tree

2 files changed

+68
-113
lines changed

2 files changed

+68
-113
lines changed

src/main/java/io/temporal/samples/encryptedpayloads/CryptDataConverter.java renamed to src/main/java/io/temporal/samples/encryptedpayloads/CryptCodec.java

Lines changed: 61 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,25 @@
1919

2020
package io.temporal.samples.encryptedpayloads;
2121

22-
import com.google.common.base.Defaults;
2322
import com.google.protobuf.ByteString;
2423
import io.temporal.api.common.v1.Payload;
25-
import io.temporal.api.common.v1.Payloads;
26-
import io.temporal.common.converter.DataConverter;
2724
import io.temporal.common.converter.DataConverterException;
28-
import java.lang.reflect.Type;
25+
import io.temporal.common.converter.EncodingKeys;
26+
import io.temporal.payload.codec.PayloadCodec;
27+
import io.temporal.payload.codec.PayloadCodecException;
2928
import java.nio.ByteBuffer;
3029
import java.nio.charset.Charset;
3130
import java.nio.charset.StandardCharsets;
3231
import java.security.SecureRandom;
33-
import java.util.Optional;
32+
import java.util.List;
33+
import java.util.stream.Collectors;
3434
import javax.crypto.Cipher;
3535
import javax.crypto.SecretKey;
3636
import javax.crypto.spec.GCMParameterSpec;
3737
import javax.crypto.spec.SecretKeySpec;
38+
import org.jetbrains.annotations.NotNull;
3839

39-
public class CryptDataConverter implements DataConverter {
40-
static final String METADATA_ENCODING_KEY = "encoding";
40+
class CryptCodec implements PayloadCodec {
4141
static final ByteString METADATA_ENCODING =
4242
ByteString.copyFrom("binary/encrypted", StandardCharsets.UTF_8);
4343

@@ -53,10 +53,61 @@ public class CryptDataConverter implements DataConverter {
5353
private static final int GCM_TAG_LENGTH_BIT = 128;
5454
private static final Charset UTF_8 = StandardCharsets.UTF_8;
5555

56-
private final DataConverter converter;
56+
@NotNull
57+
@Override
58+
public List<Payload> encode(@NotNull List<Payload> payloads) {
59+
return payloads.stream().map(this::encodePayload).collect(Collectors.toList());
60+
}
61+
62+
@NotNull
63+
@Override
64+
public List<Payload> decode(@NotNull List<Payload> payloads) {
65+
return payloads.stream().map(this::decodePayload).collect(Collectors.toList());
66+
}
67+
68+
private Payload encodePayload(Payload payload) {
69+
String keyId = getKeyId();
70+
SecretKey key = getKey(keyId);
71+
72+
byte[] encryptedData;
73+
try {
74+
encryptedData = encrypt(payload.toByteArray(), key);
75+
} catch (Throwable e) {
76+
throw new DataConverterException(e);
77+
}
5778

58-
public CryptDataConverter(DataConverter converter) {
59-
this.converter = converter;
79+
return Payload.newBuilder()
80+
.putMetadata(EncodingKeys.METADATA_ENCODING_KEY, METADATA_ENCODING)
81+
.putMetadata(METADATA_ENCRYPTION_CIPHER_KEY, METADATA_ENCRYPTION_CIPHER)
82+
.putMetadata(METADATA_ENCRYPTION_KEY_ID_KEY, ByteString.copyFromUtf8(keyId))
83+
.setData(ByteString.copyFrom(encryptedData))
84+
.build();
85+
}
86+
87+
private Payload decodePayload(Payload payload) {
88+
if (METADATA_ENCODING.equals(
89+
payload.getMetadataOrDefault(EncodingKeys.METADATA_ENCODING_KEY, null))) {
90+
String keyId;
91+
try {
92+
keyId = payload.getMetadataOrThrow(METADATA_ENCRYPTION_KEY_ID_KEY).toString(UTF_8);
93+
} catch (Exception e) {
94+
throw new PayloadCodecException(e);
95+
}
96+
SecretKey key = getKey(keyId);
97+
98+
byte[] plainData;
99+
Payload decryptedPayload;
100+
101+
try {
102+
plainData = decrypt(payload.getData().toByteArray(), key);
103+
decryptedPayload = Payload.parseFrom(plainData);
104+
return decryptedPayload;
105+
} catch (Throwable e) {
106+
throw new PayloadCodecException(e);
107+
}
108+
} else {
109+
return payload;
110+
}
60111
}
61112

62113
private String getKeyId() {
@@ -106,105 +157,4 @@ private byte[] decrypt(byte[] encryptedDataWithNonce, SecretKey key) throws Exce
106157

107158
return cipher.doFinal(encryptedData);
108159
}
109-
110-
@Override
111-
public <T> Optional<Payload> toPayload(T value) throws DataConverterException {
112-
return converter.toPayload(value);
113-
}
114-
115-
public <T> Optional<Payload> toEncryptedPayload(T value) throws DataConverterException {
116-
Optional<Payload> optionalPayload = converter.toPayload(value);
117-
118-
if (!optionalPayload.isPresent()) {
119-
return optionalPayload;
120-
}
121-
122-
Payload innerPayload = optionalPayload.get();
123-
124-
String keyId = getKeyId();
125-
SecretKey key = getKey(keyId);
126-
127-
byte[] encryptedData;
128-
try {
129-
encryptedData = encrypt(innerPayload.toByteArray(), key);
130-
} catch (Throwable e) {
131-
throw new DataConverterException(e);
132-
}
133-
134-
Payload encryptedPayload =
135-
Payload.newBuilder()
136-
.putMetadata(METADATA_ENCODING_KEY, METADATA_ENCODING)
137-
.putMetadata(METADATA_ENCRYPTION_CIPHER_KEY, METADATA_ENCRYPTION_CIPHER)
138-
.putMetadata(METADATA_ENCRYPTION_KEY_ID_KEY, ByteString.copyFromUtf8(keyId))
139-
.setData(ByteString.copyFrom(encryptedData))
140-
.build();
141-
142-
return Optional.of(encryptedPayload);
143-
}
144-
145-
@Override
146-
public <T> T fromPayload(Payload payload, Class<T> valueClass, Type valueType) {
147-
ByteString encoding = payload.getMetadataOrDefault(METADATA_ENCODING_KEY, null);
148-
if (!encoding.equals(METADATA_ENCODING)) {
149-
return converter.fromPayload(payload, valueClass, valueType);
150-
}
151-
152-
String keyId;
153-
try {
154-
keyId = payload.getMetadataOrThrow(METADATA_ENCRYPTION_KEY_ID_KEY).toString(UTF_8);
155-
} catch (Exception e) {
156-
throw new DataConverterException(payload, valueClass, e);
157-
}
158-
SecretKey key = getKey(keyId);
159-
160-
byte[] plainData;
161-
Payload decryptedPayload;
162-
163-
try {
164-
plainData = decrypt(payload.getData().toByteArray(), key);
165-
decryptedPayload = Payload.parseFrom(plainData);
166-
} catch (Throwable e) {
167-
throw new DataConverterException(e);
168-
}
169-
170-
return converter.fromPayload(decryptedPayload, valueClass, valueType);
171-
}
172-
173-
@Override
174-
public Optional<Payloads> toPayloads(Object... values) throws DataConverterException {
175-
if (values == null || values.length == 0) {
176-
return Optional.empty();
177-
}
178-
try {
179-
Payloads.Builder result = Payloads.newBuilder();
180-
for (Object value : values) {
181-
Optional<Payload> payload = toEncryptedPayload(value);
182-
if (payload.isPresent()) {
183-
result.addPayloads(payload.get());
184-
} else {
185-
result.addPayloads(Payload.getDefaultInstance());
186-
}
187-
}
188-
return Optional.of(result.build());
189-
} catch (DataConverterException e) {
190-
throw e;
191-
} catch (Throwable e) {
192-
throw new DataConverterException(e);
193-
}
194-
}
195-
196-
@Override
197-
public <T> T fromPayloads(
198-
int index, Optional<Payloads> content, Class<T> parameterType, Type genericParameterType)
199-
throws DataConverterException {
200-
if (!content.isPresent()) {
201-
return (T) Defaults.defaultValue((Class<?>) parameterType);
202-
}
203-
int count = content.get().getPayloadsCount();
204-
// To make adding arguments a backwards compatible change
205-
if (index >= count) {
206-
return (T) Defaults.defaultValue((Class<?>) parameterType);
207-
}
208-
return fromPayload(content.get().getPayloads(index), parameterType, genericParameterType);
209-
}
210160
}

src/main/java/io/temporal/samples/encryptedpayloads/EncryptedPayloadsActivity.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@
2525
import io.temporal.client.WorkflowClient;
2626
import io.temporal.client.WorkflowClientOptions;
2727
import io.temporal.client.WorkflowOptions;
28-
import io.temporal.common.converter.DataConverter;
28+
import io.temporal.common.converter.CodecDataConverter;
29+
import io.temporal.common.converter.DefaultDataConverter;
2930
import io.temporal.serviceclient.WorkflowServiceStubs;
3031
import io.temporal.worker.Worker;
3132
import io.temporal.worker.WorkerFactory;
3233
import io.temporal.workflow.Workflow;
3334
import io.temporal.workflow.WorkflowInterface;
3435
import io.temporal.workflow.WorkflowMethod;
3536
import java.time.Duration;
37+
import java.util.Collections;
3638

3739
/**
3840
* Hello World Temporal workflow that executes a single activity. Requires a local instance the
@@ -91,7 +93,10 @@ public static void main(String[] args) {
9193
WorkflowClient.newInstance(
9294
service,
9395
WorkflowClientOptions.newBuilder()
94-
.setDataConverter(new CryptDataConverter(DataConverter.getDefaultInstance()))
96+
.setDataConverter(
97+
new CodecDataConverter(
98+
DefaultDataConverter.newDefaultInstance(),
99+
Collections.singletonList(new CryptCodec())))
95100
.build());
96101

97102
// worker factory that can be used to create workers for specific task queues

0 commit comments

Comments
 (0)