mirror of https://github.com/dapr/java-sdk.git
Update state, secrets examples. Fix state toString. Ignore sdk-autogen in code coverage. (#340)
* Update state, secrets example. Fix state toString. Ignore sdk-autogen in code coverage. * Update StateClient.java * Update README.md * Update Readme.md Co-authored-by: Nghia Tran <tcnghia@gmail.com> Co-authored-by: Artur Souza <artursouza.ms@outlook.com> Co-authored-by: Nghia Tran <tcnghia@gmail.com>
This commit is contained in:
parent
9240ae81db
commit
fb8580f71b
|
@ -1,6 +1,7 @@
|
|||
ignore:
|
||||
- examples
|
||||
- sdk-tests
|
||||
- sdk-autogen
|
||||
comment:
|
||||
# Delete old comment and post new one for new coverage information.
|
||||
behavior: new
|
||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOVER: 1.14.0
|
||||
GOVER: 1.15.0
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
GOPROXY: https://proxy.golang.org
|
||||
|
|
|
@ -41,7 +41,7 @@ mvn install
|
|||
```
|
||||
### Setting Vault locally
|
||||
|
||||
Before getting into the application code, follow these steps in order to setup a local instance of Vault. This is needed for the local instances. Steps are:
|
||||
Before getting into the application code, follow these steps in order to set up a local instance of Vault. This is needed for the local instances. Steps are:
|
||||
|
||||
1. navigate to the [examples] with `cd examples`
|
||||
2. Run `docker-compose -f ./src/main/java/io/dapr/examples/secrets/docker-compose-vault.yml up -d` to run the container locally
|
||||
|
@ -61,18 +61,23 @@ Dapr's API for secret store only support read operations. For this sample to run
|
|||
vault login myroot
|
||||
```
|
||||
|
||||
> Note: If you get `http: server gave HTTP response to HTTPS client` make sure the local vault address is set `export VAULT_ADDR=http://127.0.0.1:8200/`
|
||||
> Note: If you get `http: server gave HTTP response to HTTPS client` make sure to set the local vault address as `export VAULT_ADDR=http://127.0.0.1:8200/`
|
||||
|
||||
2. Create secret (replace `[my favorite movie]` with a title of our choice):
|
||||
```bash
|
||||
vault kv put secret/dapr/movie title="[my favorite movie]"
|
||||
```
|
||||
|
||||
3. Create random secret:
|
||||
```bash
|
||||
vault kv put secret/dapr/randomKey testVal="value"
|
||||
```
|
||||
|
||||
In the command above, `secret` means the secret engine in Hashicorp's Vault.
|
||||
Then, `dapr` is the prefix as defined in `< repo dir >/examples/components/hashicorp_vault.yaml`.
|
||||
Finally, `movie` is the secret name and then a `key=value` pair.
|
||||
Finally, `movie` and `randomKey` are the secret names with the value set in the form of `key=value` pair.
|
||||
|
||||
A secret in dapr is a dictionary. In this sample, only one key-value pair is used but more can be added as an exercise for the reader.
|
||||
A secret in Dapr is a dictionary.
|
||||
|
||||
### Running the secret store sample
|
||||
|
||||
|
@ -101,6 +106,13 @@ public class SecretClient {
|
|||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
Map<String, String> secret = client.getSecret(SECRET_STORE_NAME, secretKey).block();
|
||||
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
|
||||
|
||||
try {
|
||||
secret = client.getSecret(SECRET_STORE_NAME, "randomKey").block();
|
||||
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
|
||||
} catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
///...
|
||||
|
@ -111,7 +123,7 @@ After identifying the key to be fetched, it will retrieve it from the pre-define
|
|||
The secret store's name **must** match the component's name defined in `< repo dir >/examples/components/hashicorp_vault.yaml`.
|
||||
The Dapr client is also within a try-with-resource block to properly close the client at the end.
|
||||
|
||||
Execute the follow script in order to run the example:
|
||||
Execute the following script in order to run the example:
|
||||
```sh
|
||||
cd to [repo-root]/examples
|
||||
dapr run --components-path ./components -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient movie
|
||||
|
@ -121,11 +133,44 @@ Once running, the program should print the output as follows:
|
|||
|
||||
```
|
||||
== APP == {"title":"[my favorite movie]"}
|
||||
|
||||
== APP == {"testVal":"value"}
|
||||
```
|
||||
|
||||
To close the app, press CTRL+c.
|
||||
|
||||
To cleanup and bring the vault container down, run
|
||||
The example's `config.yaml` is as follows:
|
||||
```yaml
|
||||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: daprConfig
|
||||
spec:
|
||||
secrets:
|
||||
scopes:
|
||||
- storeName: "vault"
|
||||
defaultAccess: "deny"
|
||||
allowedSecrets: ["movie",]
|
||||
```
|
||||
|
||||
The configuration defines, that the only allowed secret is `movie` and all other secrets are denied.
|
||||
|
||||
Execute the following script in order to run this example with additional secret scoping:
|
||||
```sh
|
||||
cd to [repo-root]/examples
|
||||
dapr run --components-path ./components --config ./src/main/java/io/dapr/examples/secrets/config.yaml -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.secrets.SecretClient movie
|
||||
```
|
||||
Once running, the program should print the output as follows:
|
||||
|
||||
```
|
||||
== APP == {"title":"[my favorite movie]"}
|
||||
|
||||
== APP == java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Access denied by policy to get randomKey from vault
|
||||
```
|
||||
|
||||
To close the app, press CTRL+c.
|
||||
|
||||
To clean up and bring the vault container down, run
|
||||
```sh
|
||||
docker-compose -f ./src/main/java/io/dapr/examples/secrets/docker-compose-vault.yml down
|
||||
```
|
||||
|
|
|
@ -48,6 +48,13 @@ public class SecretClient {
|
|||
try (DaprClient client = (new DaprClientBuilder()).build()) {
|
||||
Map<String, String> secret = client.getSecret(SECRET_STORE_NAME, secretKey).block();
|
||||
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
|
||||
|
||||
try {
|
||||
secret = client.getSecret(SECRET_STORE_NAME, "randomKey").block();
|
||||
System.out.println(JSON_SERIALIZER.writeValueAsString(secret));
|
||||
} catch (Exception ex) {
|
||||
System.out.println(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: daprConfig
|
||||
spec:
|
||||
secrets:
|
||||
scopes:
|
||||
- storeName: "vault"
|
||||
defaultAccess: "deny"
|
||||
allowedSecrets: ["movie",]
|
|
@ -37,7 +37,9 @@ public class StateClient {
|
|||
///...
|
||||
private static final String STATE_STORE_NAME = "statestore";
|
||||
|
||||
private static final String KEY_NAME = "mykey";
|
||||
private static final String FIRST_KEY_NAME = "myKey";
|
||||
|
||||
private static final String SECOND_KEY_NAME = "myKey2";
|
||||
///...
|
||||
public static void main(String[] args) throws IOException {
|
||||
try (DaprClient client = new DaprClientBuilder().build()) {
|
||||
|
@ -45,19 +47,51 @@ public class StateClient {
|
|||
|
||||
MyClass myClass = new MyClass();
|
||||
myClass.message = message;
|
||||
MyClass secondState = new MyClass();
|
||||
secondState.message = "test message";
|
||||
|
||||
client.saveState(STATE_STORE_NAME, KEY_NAME, myClass).block();
|
||||
client.saveState(STATE_STORE_NAME, FIRST_KEY_NAME, myClass).block();
|
||||
System.out.println("Saving class with message: " + message);
|
||||
|
||||
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
|
||||
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class);
|
||||
System.out.println("Retrieved class message from state: " + (retrievedMessageMono.block().getValue()).message);
|
||||
|
||||
System.out.println("Deleting state...");
|
||||
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, KEY_NAME);
|
||||
System.out.println("Updating previous state and adding another state 'test state'... ");
|
||||
myClass.message = message + " updated";
|
||||
System.out.println("Saving updated class with message: " + myClass.message);
|
||||
|
||||
// execute transaction
|
||||
List<TransactionalStateOperation<?>> operationList = new ArrayList<>();
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
|
||||
new State<>(myClass, FIRST_KEY_NAME, "")));
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
|
||||
new State<>(secondState, SECOND_KEY_NAME, "")));
|
||||
|
||||
client.executeTransaction(STATE_STORE_NAME, operationList).block();
|
||||
|
||||
// get multiple states
|
||||
Mono<List<State<MyClass>>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME,
|
||||
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
|
||||
System.out.println("Retrieved messages using bulk get:");
|
||||
retrievedMessagesMono.block().forEach(System.out::println);
|
||||
|
||||
System.out.println("Deleting states...");
|
||||
|
||||
// delete state API
|
||||
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME);
|
||||
mono.block();
|
||||
|
||||
Mono<State<MyClass>> retrievedDeletedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
|
||||
System.out.println("Trying to retrieve deleted state: " + retrievedDeletedMessageMono.block().getValue());
|
||||
// Delete operation using transaction API
|
||||
operationList.clear();
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE,
|
||||
new State<>(SECOND_KEY_NAME)));
|
||||
mono = client.executeTransaction(STATE_STORE_NAME, operationList);
|
||||
mono.block();
|
||||
|
||||
Mono<List<State<MyClass>>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME,
|
||||
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
|
||||
System.out.println("Trying to retrieve deleted states: ");
|
||||
retrievedDeletedMessageMono.block().forEach(System.out::println);
|
||||
|
||||
// This is an example, so for simplicity we are just exiting here.
|
||||
// Normally a dapr app would be a web service and not exit main.
|
||||
|
@ -66,7 +100,19 @@ public class StateClient {
|
|||
}
|
||||
}
|
||||
```
|
||||
The code uses the `DaprClient` created by the `DaprClientBuilder`. Notice that this builder uses default settings. Internally, it is using `DefaultObjectSerializer` for two properties: `objectSerializer` is for Dapr's sent and received objects, and `stateSerializer` is for objects to be persisted. This client performs three operations: `client.saveState(...)` for persisting an instance of `MyClass`, then uses the `client.getState(...)` operation in order to retrieve back the persisted state using the same key. `client.deleteState(...)` operation is used to remove the persisted state. Finally, the code tries to retrieve the deleted state, which should not be found. The Dapr client is also within a try-with-resource block to properly close the client at the end.
|
||||
The code uses the `DaprClient` created by the `DaprClientBuilder`. Notice that this builder uses default settings. Internally, it is using `DefaultObjectSerializer` for two properties: `objectSerializer` is for Dapr's sent and received objects, and `stateSerializer` is for objects to be persisted.
|
||||
|
||||
This example performs multiple operations:
|
||||
* `client.saveState(...)` for persisting an instance of `MyClass`.
|
||||
* `client.getState(...)` operation in order to retrieve back the persisted state using the same key.
|
||||
* `client.executeTransaction(...)` operation in order to update existing state and add new state.
|
||||
* `client.getStates(...)` operation in order to retrieve back the persisted states using the same keys.
|
||||
* `client.deleteState(...)` operation to remove one of the persisted states.
|
||||
* `client.executeTransaction(...)` operation in order to remove the other persisted state.
|
||||
|
||||
Finally, the code tries to retrieve the deleted states, which should not be found.
|
||||
|
||||
The Dapr client is also within a try-with-resource block to properly close the client at the end.
|
||||
|
||||
### Running the example
|
||||
|
||||
|
|
|
@ -8,9 +8,13 @@ package io.dapr.examples.state;
|
|||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.client.DaprClientBuilder;
|
||||
import io.dapr.client.domain.State;
|
||||
import io.dapr.client.domain.TransactionalStateOperation;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 1. Build and install jars:
|
||||
|
@ -24,11 +28,18 @@ public class StateClient {
|
|||
|
||||
public static class MyClass {
|
||||
public String message;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String STATE_STORE_NAME = "statestore";
|
||||
|
||||
private static final String KEY_NAME = "myKey";
|
||||
private static final String FIRST_KEY_NAME = "myKey";
|
||||
|
||||
private static final String SECOND_KEY_NAME = "myKey2";
|
||||
|
||||
/**
|
||||
* Executes the sate actions.
|
||||
|
@ -40,19 +51,51 @@ public class StateClient {
|
|||
|
||||
MyClass myClass = new MyClass();
|
||||
myClass.message = message;
|
||||
MyClass secondState = new MyClass();
|
||||
secondState.message = "test message";
|
||||
|
||||
client.saveState(STATE_STORE_NAME, KEY_NAME, myClass).block();
|
||||
client.saveState(STATE_STORE_NAME, FIRST_KEY_NAME, myClass).block();
|
||||
System.out.println("Saving class with message: " + message);
|
||||
|
||||
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
|
||||
Mono<State<MyClass>> retrievedMessageMono = client.getState(STATE_STORE_NAME, FIRST_KEY_NAME, MyClass.class);
|
||||
System.out.println("Retrieved class message from state: " + (retrievedMessageMono.block().getValue()).message);
|
||||
|
||||
System.out.println("Deleting state...");
|
||||
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, KEY_NAME);
|
||||
System.out.println("Updating previous state and adding another state 'test state'... ");
|
||||
myClass.message = message + " updated";
|
||||
System.out.println("Saving updated class with message: " + myClass.message);
|
||||
|
||||
// execute transaction
|
||||
List<TransactionalStateOperation<?>> operationList = new ArrayList<>();
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
|
||||
new State<>(myClass, FIRST_KEY_NAME, "")));
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT,
|
||||
new State<>(secondState, SECOND_KEY_NAME, "")));
|
||||
|
||||
client.executeTransaction(STATE_STORE_NAME, operationList).block();
|
||||
|
||||
// get multiple states
|
||||
Mono<List<State<MyClass>>> retrievedMessagesMono = client.getStates(STATE_STORE_NAME,
|
||||
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
|
||||
System.out.println("Retrieved messages using bulk get:");
|
||||
retrievedMessagesMono.block().forEach(System.out::println);
|
||||
|
||||
System.out.println("Deleting states...");
|
||||
|
||||
// delete state API
|
||||
Mono<Void> mono = client.deleteState(STATE_STORE_NAME, FIRST_KEY_NAME);
|
||||
mono.block();
|
||||
|
||||
Mono<State<MyClass>> retrievedDeletedMessageMono = client.getState(STATE_STORE_NAME, KEY_NAME, MyClass.class);
|
||||
System.out.println("Trying to retrieve deleted state: " + retrievedDeletedMessageMono.block().getValue());
|
||||
// Delete operation using transaction API
|
||||
operationList.clear();
|
||||
operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE,
|
||||
new State<>(SECOND_KEY_NAME)));
|
||||
mono = client.executeTransaction(STATE_STORE_NAME, operationList);
|
||||
mono.block();
|
||||
|
||||
Mono<List<State<MyClass>>> retrievedDeletedMessageMono = client.getStates(STATE_STORE_NAME,
|
||||
Arrays.asList(FIRST_KEY_NAME, SECOND_KEY_NAME), MyClass.class);
|
||||
System.out.println("Trying to retrieve deleted states: ");
|
||||
retrievedDeletedMessageMono.block().forEach(System.out::println);
|
||||
|
||||
// This is an example, so for simplicity we are just exiting here.
|
||||
// Normally a dapr app would be a web service and not exit main.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 150 KiB |
|
@ -214,8 +214,8 @@ public class State<T> {
|
|||
+ "value=" + value
|
||||
+ ", key='" + key + "'"
|
||||
+ ", etag='" + etag + "'"
|
||||
+ ", etag='" + error + "'"
|
||||
+ ", options={'" + (options != null ? options.toString() : null) + "}"
|
||||
+ ", error='" + error + "'"
|
||||
+ ", options={'" + (options != null ? options.toString() : null) + "'}"
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
|||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
@ -662,7 +663,9 @@ public class DaprClientGrpcTest {
|
|||
State<String> keyRequest = buildStateKey(null, key, etag, null);
|
||||
Mono<State<String>> result = adapter.getState(STATE_STORE_NAME, keyRequest, String.class);
|
||||
settableFuture.set(responseEnvelope);
|
||||
assertEquals(expectedState, result.block());
|
||||
State<String> res = result.block();
|
||||
assertNotNull(res);
|
||||
assertEquals(expectedState, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -705,7 +708,9 @@ public class DaprClientGrpcTest {
|
|||
.thenReturn(settableFuture);
|
||||
Mono<State<MyObject>> result = adapter.getState(STATE_STORE_NAME, keyRequest, MyObject.class);
|
||||
settableFuture.set(responseEnvelope);
|
||||
assertEquals(expectedState, result.block());
|
||||
State<MyObject> res = result.block();
|
||||
assertNotNull(res);
|
||||
assertEquals(expectedState, res);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -731,7 +736,9 @@ public class DaprClientGrpcTest {
|
|||
.thenReturn(settableFuture);
|
||||
Mono<Response<State<MyObject>>> result = adapter.getState(request, TypeRef.get(MyObject.class));
|
||||
settableFuture.set(responseEnvelope);
|
||||
assertEquals(expectedState, result.block().getObject());
|
||||
Response<State<MyObject>> res = result.block();
|
||||
assertNotNull(res);
|
||||
assertEquals(expectedState, res.getObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package io.dapr.client.domain;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class StateTest {
|
||||
|
||||
private static final String KEY = "key";
|
||||
private static final String ETAG = "111";
|
||||
private static final StateOptions OPTIONS = new StateOptions(StateOptions.Consistency.STRONG,
|
||||
StateOptions.Concurrency.FIRST_WRITE);
|
||||
|
||||
@Test
|
||||
public void testSimpleStringState() {
|
||||
State<String> state = new State<>("value", KEY, ETAG);
|
||||
assertNotNull(state);
|
||||
assertNull(state.getError());
|
||||
assertNull(state.getOptions());
|
||||
assertEquals(KEY, state.getKey());
|
||||
assertEquals(ETAG, state.getEtag());
|
||||
assertEquals("value", state.getValue());
|
||||
String expected = "StateKeyValue{"
|
||||
+ "value=value"
|
||||
+ ", key='" + KEY + "'"
|
||||
+ ", etag='" + ETAG + "'"
|
||||
+ ", error='null'"
|
||||
+ ", options={'null'}"
|
||||
+ "}";;
|
||||
assertEquals(expected, state.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringState() {
|
||||
State<String> state = new State<>(KEY, ETAG, OPTIONS);
|
||||
assertNotNull(state);
|
||||
assertNull(state.getError());
|
||||
assertNull(state.getValue());
|
||||
assertEquals(OPTIONS, state.getOptions());
|
||||
assertEquals(KEY, state.getKey());
|
||||
assertEquals(ETAG, state.getEtag());
|
||||
String expected = "StateKeyValue{"
|
||||
+ "value=null"
|
||||
+ ", key='" + KEY + "'"
|
||||
+ ", etag='" + ETAG + "'"
|
||||
+ ", error='null'"
|
||||
+ ", options={'" + OPTIONS.toString() + "'}"
|
||||
+ "}";;
|
||||
assertEquals(expected, state.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleStringStateWithOptions() {
|
||||
State<String> state = new State<>("value", KEY, ETAG, OPTIONS);
|
||||
assertNotNull(state);
|
||||
assertNull(state.getError());
|
||||
assertEquals(OPTIONS, state.getOptions());
|
||||
assertEquals(KEY, state.getKey());
|
||||
assertEquals(ETAG, state.getEtag());
|
||||
String expected = "StateKeyValue{"
|
||||
+ "value=value"
|
||||
+ ", key='" + KEY + "'"
|
||||
+ ", etag='" + ETAG + "'"
|
||||
+ ", error='null'"
|
||||
+ ", options={'" + OPTIONS.toString() + "'}"
|
||||
+ "}";;
|
||||
assertEquals(expected, state.toString());
|
||||
assertEquals("value", state.getValue());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue