mirror of https://github.com/dapr/java-sdk.git
Strong typed actors. (#243)
This commit is contained in:
parent
85e9d2de02
commit
7fd4e39b56
|
@ -5,11 +5,14 @@
|
||||||
|
|
||||||
package io.dapr.examples.actors.http;
|
package io.dapr.examples.actors.http;
|
||||||
|
|
||||||
|
import io.dapr.actors.ActorMethod;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example of implementation of an Actor.
|
* Example of implementation of an Actor.
|
||||||
*/
|
*/
|
||||||
|
@ActorType(name = "DemoActor")
|
||||||
public interface DemoActor {
|
public interface DemoActor {
|
||||||
|
|
||||||
void registerReminder();
|
void registerReminder();
|
||||||
|
@ -18,5 +21,6 @@ public interface DemoActor {
|
||||||
|
|
||||||
void clock(String message);
|
void clock(String message);
|
||||||
|
|
||||||
|
@ActorMethod(returns = Integer.class)
|
||||||
Mono<Integer> incrementAndGet(int delta);
|
Mono<Integer> incrementAndGet(int delta);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
package io.dapr.examples.actors.http;
|
package io.dapr.examples.actors.http;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
|
||||||
import io.dapr.actors.client.ActorProxyBuilder;
|
import io.dapr.actors.client.ActorProxyBuilder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -30,16 +29,17 @@ public class DemoActorClient {
|
||||||
* @throws InterruptedException If program has been interrupted.
|
* @throws InterruptedException If program has been interrupted.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws InterruptedException {
|
public static void main(String[] args) throws InterruptedException {
|
||||||
ActorProxyBuilder builder = new ActorProxyBuilder("DemoActor");
|
ActorProxyBuilder<DemoActor> builder = new ActorProxyBuilder(DemoActor.class);
|
||||||
|
|
||||||
List<Thread> threads = new ArrayList<>(NUM_ACTORS);
|
List<Thread> threads = new ArrayList<>(NUM_ACTORS);
|
||||||
|
|
||||||
// Creates multiple actors.
|
// Creates multiple actors.
|
||||||
for (int i = 0; i < NUM_ACTORS; i++) {
|
for (int i = 0; i < NUM_ACTORS; i++) {
|
||||||
ActorProxy actor = builder.build(ActorId.createRandom());
|
ActorId actorId = ActorId.createRandom();
|
||||||
|
DemoActor actor = builder.build(actorId);
|
||||||
|
|
||||||
// Start a thread per actor.
|
// Start a thread per actor.
|
||||||
Thread thread = new Thread(() -> callActorForever(actor));
|
Thread thread = new Thread(() -> callActorForever(actorId.toString(), actor));
|
||||||
thread.start();
|
thread.start();
|
||||||
threads.add(thread);
|
threads.add(thread);
|
||||||
}
|
}
|
||||||
|
@ -54,21 +54,22 @@ public class DemoActorClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes multiple method calls into actor until interrupted.
|
* Makes multiple method calls into actor until interrupted.
|
||||||
|
* @param actorId Actor's identifier.
|
||||||
* @param actor Actor to be invoked.
|
* @param actor Actor to be invoked.
|
||||||
*/
|
*/
|
||||||
private static final void callActorForever(ActorProxy actor) {
|
private static final void callActorForever(String actorId, DemoActor actor) {
|
||||||
// First, register reminder.
|
// First, register reminder.
|
||||||
actor.invokeActorMethod("registerReminder").block();
|
actor.registerReminder();
|
||||||
|
|
||||||
// Now, we run until thread is interrupted.
|
// Now, we run until thread is interrupted.
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
// Invoke actor method to increment counter by 1, then build message.
|
// Invoke actor method to increment counter by 1, then build message.
|
||||||
int messageNumber = actor.invokeActorMethod("incrementAndGet", 1, int.class).block();
|
int messageNumber = actor.incrementAndGet(1).block();
|
||||||
String message = String.format("Actor %s said message #%d", actor.getActorId().toString(), messageNumber);
|
String message = String.format("Actor %s said message #%d", actorId, messageNumber);
|
||||||
|
|
||||||
// Invoke the 'say' method in actor.
|
// Invoke the 'say' method in actor.
|
||||||
String result = actor.invokeActorMethod("say", message, String.class).block();
|
String result = actor.say(message);
|
||||||
System.out.println(String.format("Actor %s got a reply: %s", actor.getActorId().toString(), result));
|
System.out.println(String.format("Actor %s got a reply: %s", actorId, result));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Waits for up to 1 second.
|
// Waits for up to 1 second.
|
||||||
|
|
|
@ -8,7 +8,6 @@ package io.dapr.examples.actors.http;
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
import io.dapr.actors.runtime.AbstractActor;
|
import io.dapr.actors.runtime.AbstractActor;
|
||||||
import io.dapr.actors.runtime.ActorRuntimeContext;
|
import io.dapr.actors.runtime.ActorRuntimeContext;
|
||||||
import io.dapr.actors.runtime.ActorType;
|
|
||||||
import io.dapr.actors.runtime.Remindable;
|
import io.dapr.actors.runtime.Remindable;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
@ -21,7 +20,6 @@ import java.util.TimeZone;
|
||||||
/**
|
/**
|
||||||
* Implementation of the DemoActor for the server side.
|
* Implementation of the DemoActor for the server side.
|
||||||
*/
|
*/
|
||||||
@ActorType(name = "DemoActor")
|
|
||||||
public class DemoActorImpl extends AbstractActor implements DemoActor, Remindable<Integer> {
|
public class DemoActorImpl extends AbstractActor implements DemoActor, Remindable<Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -35,7 +35,7 @@ mvn install
|
||||||
|
|
||||||
### Running the Demo actor service
|
### Running the Demo actor service
|
||||||
|
|
||||||
The first element is to run is `DemoActorService`. Its job is registering the `DemoActor` implementation in the Dapr's Actor runtime. In `DemoActorService.java` file, you will find the `DemoActorService` class and the `main` method. See the code snippet below:
|
The first Java class is `DemoActorService`. Its job is to register an implementation of `DemoActor` in the Dapr's Actor runtime. In `DemoActorService.java` file, you will find the `DemoActorService` class and the `main` method. See the code snippet below:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@ -59,7 +59,6 @@ This application uses `ActorRuntime.getInstance().registerActor()` in order to r
|
||||||
|
|
||||||
See [DemoActorImpl](DemoActorImpl.java) for details on the implementation of an actor:
|
See [DemoActorImpl](DemoActorImpl.java) for details on the implementation of an actor:
|
||||||
```java
|
```java
|
||||||
@ActorType(name = "DemoActor")
|
|
||||||
public class DemoActorImpl extends AbstractActor implements DemoActor, Remindable<Integer> {
|
public class DemoActorImpl extends AbstractActor implements DemoActor, Remindable<Integer> {
|
||||||
//...
|
//...
|
||||||
|
|
||||||
|
@ -99,7 +98,28 @@ public class DemoActorImpl extends AbstractActor implements DemoActor, Remindabl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
An actor inherits from `AbstractActor` and implements the constructor to pass through `ActorRuntimeContext` and `ActorId`. By default, the actor's name will be the same as the class' name. Optionally, it can be annotated with `ActorType` and override the actor's name. The actor's methods can be synchronously or use [Project Reactor's Mono](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html) return type. Finally, state management is done via methods in `super.getActorStateManager()`.
|
An actor inherits from `AbstractActor` and implements the constructor to pass through `ActorRuntimeContext` and `ActorId`. By default, the actor's name will be the same as the class' name. Optionally, it can be annotated with `ActorType` and override the actor's name. The actor's methods can be synchronously or use [Project Reactor's Mono](https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html) return type. Finally, state management is done via methods in `super.getActorStateManager()`. The `DemoActor` interface is used by the Actor runtime and also client. See how `DemoActor` interface can be annotated as Dapr Actor.
|
||||||
|
|
||||||
|
```java
|
||||||
|
/**
|
||||||
|
* Example of implementation of an Actor.
|
||||||
|
*/
|
||||||
|
@ActorType(name = "DemoActor")
|
||||||
|
public interface DemoActor {
|
||||||
|
|
||||||
|
void registerReminder();
|
||||||
|
|
||||||
|
String say(String something);
|
||||||
|
|
||||||
|
void clock(String message);
|
||||||
|
|
||||||
|
@ActorMethod(returns = Integer.class)
|
||||||
|
Mono<Integer> incrementAndGet(int delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The `@ActorType` annotation indicates the Dapr Java SDK that this interface is an Actor Type, allowing a name for the type to be defined. Some methods can return a `Mono` object. In these cases, the `@ActorMethod` annotation is used to hint the Dapr Java SDK of the type encapsulated in the `Mono` object. You can read more about Java generic type erasure [here](https://docs.oracle.com/javase/tutorial/java/generics/erasure.html).
|
||||||
|
|
||||||
|
|
||||||
Now, execute the following script in order to run DemoActorService:
|
Now, execute the following script in order to run DemoActorService:
|
||||||
|
@ -120,31 +140,32 @@ public class DemoActorClient {
|
||||||
private static final int NUM_ACTORS = 3;
|
private static final int NUM_ACTORS = 3;
|
||||||
|
|
||||||
public static void main(String[] args) throws InterruptedException {
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
ActorProxyBuilder<DemoActor> builder = new ActorProxyBuilder(DemoActor.class);
|
||||||
///...
|
///...
|
||||||
for (int i = 0; i < NUM_ACTORS; i++) {
|
for (int i = 0; i < NUM_ACTORS; i++) {
|
||||||
ActorProxy actor = builder.build(ActorId.createRandom());
|
DemoActor actor = builder.build(ActorId.createRandom());
|
||||||
|
|
||||||
// Start a thread per actor.
|
// Start a thread per actor.
|
||||||
Thread thread = new Thread(() -> callActorForever(actor));
|
Thread thread = new Thread(() -> callActorForever(actorId.toString(), actor));
|
||||||
thread.start();
|
thread.start();
|
||||||
threads.add(thread);
|
threads.add(thread);
|
||||||
}
|
}
|
||||||
///...
|
///...
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final void callActorForever(ActorProxy actor) {
|
private static final void callActorForever(String actorId, DemoActor actor) {
|
||||||
// First, register reminder.
|
// First, register reminder.
|
||||||
actor.invokeActorMethod("registerReminder").block();
|
actor.registerReminder();
|
||||||
|
|
||||||
// Now, we run until thread is interrupted.
|
// Now, we run until thread is interrupted.
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
// Invoke actor method to increment counter by 1, then build message.
|
// Invoke actor method to increment counter by 1, then build message.
|
||||||
int messageNumber = actor.invokeActorMethod("incrementAndGet", 1, int.class).block();
|
int messageNumber = actor.incrementAndGet(1).block();
|
||||||
String message = String.format("Actor %s said message #%d", actor.getActorId().toString(), messageNumber);
|
String message = String.format("Actor %s said message #%d", actorId, messageNumber);
|
||||||
|
|
||||||
// Invoke the 'say' method in actor.
|
// Invoke the 'say' method in actor.
|
||||||
String result = actor.invokeActorMethod("say", message, String.class).block();
|
String result = actor.say(message);
|
||||||
System.out.println(String.format("Actor %s got a reply: %s", actor.getActorId().toString(), result));
|
System.out.println(String.format("Actor %s got a reply: %s", actorId, result));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Waits for up to 1 second.
|
// Waits for up to 1 second.
|
||||||
|
@ -158,7 +179,7 @@ public class DemoActorClient {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
First, the client defines how many actors it is going to create. Then the main method declares a `ActorProxyBuilder` for the `DemoActor` class to create `ActorProxy` instances, which are the actor representation provided by the SDK. The code executes the `callActorForever` private method once per actor. This method triggers the DemoActor's implementation by using `actor.invokeActorMethod()`. Initially, it will invoke `registerReminder()`, which sets the due time and period for the reminder. Then, `incrementAndGet()` increments a counter, persists it and sends it back as response. Finally `say` method which will print a message containing the received string along with the formatted server time.
|
First, the client defines how many actors it is going to create. Then the main method declares a `ActorProxyBuilder` to create instances of the `DemoActor` interface, which are implemented automatically by the SDK and make remote calls to the equivalent methods in Actor runtime. The code executes the `callActorForever` private method once per actor. Initially, it will invoke `registerReminder()`, which sets the due time and period for the reminder. Then, `incrementAndGet()` increments a counter, persists it and sends it back as response. Finally `say` method which will print a message containing the received string along with the formatted server time.
|
||||||
|
|
||||||
Use the follow command to execute the DemoActorClient:
|
Use the follow command to execute the DemoActorClient:
|
||||||
|
|
||||||
|
@ -180,5 +201,10 @@ After invoking `incrementAndGet`, the code invokes `say` method (you'll see thes
|
||||||
On the other hand, the console for `DemoActorService` is also responding to the remote invocations:
|
On the other hand, the console for `DemoActorService` is also responding to the remote invocations:
|
||||||

|

|
||||||
|
|
||||||
|
For more details on Dapr SpringBoot integration, please refer to [Dapr Spring Boot](../../springboot/DaprApplication.java) Application implementation.
|
||||||
|
|
||||||
For more details on Dapr SpringBoot integration, please refer to [Dapr Spring Boot](../../springboot/DaprApplication.java) Application implementation.
|
### Limitations
|
||||||
|
|
||||||
|
Currently, these are the limitations in the Java SDK for Dapr:
|
||||||
|
* Actor interface cannot have overloaded methods (methods with same name but different signature).
|
||||||
|
* Actor methods can only have zero or one parameter.
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
* Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.actors;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface ActorMethod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor's method return type. This is required when result object is within a Mono response.
|
||||||
|
*
|
||||||
|
* @return Actor's method return type.
|
||||||
|
*/
|
||||||
|
Class returns();
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* Licensed under the MIT License.
|
* Licensed under the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors;
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
* Licensed under the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.dapr.actors;
|
||||||
|
|
||||||
|
public final class ActorUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the actor type name for the given class or interface.
|
||||||
|
*
|
||||||
|
* @param actorClass Class or interface for Actor Type.
|
||||||
|
* @return Name for Actor Type.
|
||||||
|
*/
|
||||||
|
public static String findActorTypeName(Class<?> actorClass) {
|
||||||
|
if (actorClass == null) {
|
||||||
|
throw new IllegalArgumentException("ActorClass is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> node = actorClass;
|
||||||
|
while ((node != null) && (node.getAnnotation(ActorType.class) == null)) {
|
||||||
|
node = node.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
// No annotation found in parent classes, so we scan interfaces.
|
||||||
|
for (Class<?> interfaze : actorClass.getInterfaces()) {
|
||||||
|
if (interfaze.getAnnotation(ActorType.class) != null) {
|
||||||
|
node = interfaze;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == null) {
|
||||||
|
// No ActorType annotation found, so we use the class name.
|
||||||
|
return actorClass.getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorType actorTypeAnnotation = node.getAnnotation(ActorType.class);
|
||||||
|
return actorTypeAnnotation != null ? actorTypeAnnotation.name() : actorClass.getSimpleName();
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,14 +6,17 @@
|
||||||
package io.dapr.actors.client;
|
package io.dapr.actors.client;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorUtils;
|
||||||
import io.dapr.client.DaprHttpBuilder;
|
import io.dapr.client.DaprHttpBuilder;
|
||||||
import io.dapr.serializer.DaprObjectSerializer;
|
import io.dapr.serializer.DaprObjectSerializer;
|
||||||
import io.dapr.serializer.DefaultObjectSerializer;
|
import io.dapr.serializer.DefaultObjectSerializer;
|
||||||
|
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder to generate an ActorProxy instance. Builder can be reused for multiple instances.
|
* Builder to generate an ActorProxy instance. Builder can be reused for multiple instances.
|
||||||
*/
|
*/
|
||||||
public class ActorProxyBuilder {
|
public class ActorProxyBuilder<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for Dapr's raw http client.
|
* Builder for Dapr's raw http client.
|
||||||
|
@ -25,6 +28,11 @@ public class ActorProxyBuilder {
|
||||||
*/
|
*/
|
||||||
private final String actorType;
|
private final String actorType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor's type class.
|
||||||
|
*/
|
||||||
|
private final Class<T> clazz;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dapr's object serializer.
|
* Dapr's object serializer.
|
||||||
*/
|
*/
|
||||||
|
@ -35,15 +43,31 @@ public class ActorProxyBuilder {
|
||||||
*
|
*
|
||||||
* {@link DefaultObjectSerializer} is not recommended for production scenarios.
|
* {@link DefaultObjectSerializer} is not recommended for production scenarios.
|
||||||
*
|
*
|
||||||
* @param actorType Actor's type.
|
* @param actorTypeClass Actor's type class.
|
||||||
*/
|
*/
|
||||||
public ActorProxyBuilder(String actorType) {
|
public ActorProxyBuilder(Class<T> actorTypeClass) {
|
||||||
|
this(ActorUtils.findActorTypeName(actorTypeClass), actorTypeClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new builder for a given Actor type, using {@link DefaultObjectSerializer} by default.
|
||||||
|
*
|
||||||
|
* {@link DefaultObjectSerializer} is not recommended for production scenarios.
|
||||||
|
*
|
||||||
|
* @param actorType Actor's type.
|
||||||
|
* @param actorTypeClass Actor's type class.
|
||||||
|
*/
|
||||||
|
public ActorProxyBuilder(String actorType, Class<T> actorTypeClass) {
|
||||||
if ((actorType == null) || actorType.isEmpty()) {
|
if ((actorType == null) || actorType.isEmpty()) {
|
||||||
throw new IllegalArgumentException("ActorType is required.");
|
throw new IllegalArgumentException("ActorType is required.");
|
||||||
}
|
}
|
||||||
|
if (actorTypeClass == null) {
|
||||||
|
throw new IllegalArgumentException("ActorTypeClass is required.");
|
||||||
|
}
|
||||||
|
|
||||||
this.actorType = actorType;
|
this.actorType = actorType;
|
||||||
this.objectSerializer = new DefaultObjectSerializer();
|
this.objectSerializer = new DefaultObjectSerializer();
|
||||||
|
this.clazz = actorTypeClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,16 +91,26 @@ public class ActorProxyBuilder {
|
||||||
* @param actorId Actor's identifier.
|
* @param actorId Actor's identifier.
|
||||||
* @return New instance of ActorProxy.
|
* @return New instance of ActorProxy.
|
||||||
*/
|
*/
|
||||||
public ActorProxy build(ActorId actorId) {
|
public T build(ActorId actorId) {
|
||||||
if (actorId == null) {
|
if (actorId == null) {
|
||||||
throw new IllegalArgumentException("Cannot instantiate an Actor without Id.");
|
throw new IllegalArgumentException("Cannot instantiate an Actor without Id.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ActorProxyImpl(
|
ActorProxyImpl proxy = new ActorProxyImpl(
|
||||||
this.actorType,
|
this.actorType,
|
||||||
actorId,
|
actorId,
|
||||||
this.objectSerializer,
|
this.objectSerializer,
|
||||||
new DaprHttpClient(this.daprHttpBuilder.build()));
|
new DaprHttpClient(this.daprHttpBuilder.build()));
|
||||||
|
|
||||||
|
if (this.clazz.equals(ActorProxy.class)) {
|
||||||
|
// If users want to use the not strongly typed API, we respect that here.
|
||||||
|
return (T) proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) Proxy.newProxyInstance(
|
||||||
|
ActorProxyImpl.class.getClassLoader(),
|
||||||
|
new Class[]{this.clazz},
|
||||||
|
proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,18 @@
|
||||||
package io.dapr.actors.client;
|
package io.dapr.actors.client;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
import io.dapr.actors.runtime.ActorObjectSerializer;
|
import io.dapr.actors.ActorMethod;
|
||||||
import io.dapr.serializer.DaprObjectSerializer;
|
import io.dapr.serializer.DaprObjectSerializer;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a proxy client for an Actor's instance.
|
* Implements a proxy client for an Actor's instance.
|
||||||
*/
|
*/
|
||||||
class ActorProxyImpl implements ActorProxy {
|
class ActorProxyImpl implements ActorProxy, InvocationHandler {
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializer used for internal objects.
|
|
||||||
*/
|
|
||||||
private static final ActorObjectSerializer INTERNAL_SERIALIZER = new ActorObjectSerializer();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actor's identifier for this Actor instance.
|
* Actor's identifier for this Actor instance.
|
||||||
|
@ -107,6 +104,45 @@ class ActorProxyImpl implements ActorProxy {
|
||||||
return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, this.serialize(data)).then();
|
return this.daprClient.invokeActorMethod(actorType, actorId.toString(), methodName, this.serialize(data)).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles an invocation via reflection.
|
||||||
|
*
|
||||||
|
* @param proxy Interface or class being invoked.
|
||||||
|
* @param method Method being invoked.
|
||||||
|
* @param args Arguments to invoke method.
|
||||||
|
* @return Response object for the invocation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||||
|
if (method.getParameterCount() > 1) {
|
||||||
|
throw new UnsupportedOperationException("Actor methods can only have zero or one arguments.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getParameterCount() == 0) {
|
||||||
|
if (method.getReturnType().equals(Mono.class)) {
|
||||||
|
ActorMethod actorMethodAnnotation = method.getDeclaredAnnotation(ActorMethod.class);
|
||||||
|
if (actorMethodAnnotation == null) {
|
||||||
|
return invokeActorMethod(method.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return invokeActorMethod(method.getName(), actorMethodAnnotation.returns());
|
||||||
|
}
|
||||||
|
|
||||||
|
return invokeActorMethod(method.getName(), method.getReturnType()).block();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getReturnType().equals(Mono.class)) {
|
||||||
|
ActorMethod actorMethodAnnotation = method.getDeclaredAnnotation(ActorMethod.class);
|
||||||
|
if (actorMethodAnnotation == null) {
|
||||||
|
return invokeActorMethod(method.getName(), args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return invokeActorMethod(method.getName(), args[0], actorMethodAnnotation.returns());
|
||||||
|
}
|
||||||
|
|
||||||
|
return invokeActorMethod(method.getName(), args[0], method.getReturnType()).block();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the response object from the Actor's method result.
|
* Extracts the response object from the Actor's method result.
|
||||||
*
|
*
|
||||||
|
@ -138,5 +174,4 @@ class ActorProxyImpl implements ActorProxy {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
|
import io.dapr.actors.ActorUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -143,9 +145,8 @@ final class ActorTypeInformation<T> {
|
||||||
|
|
||||||
boolean isAbstract = Modifier.isAbstract(actorClass.getModifiers());
|
boolean isAbstract = Modifier.isAbstract(actorClass.getModifiers());
|
||||||
boolean isRemindable = ActorTypeUtilities.isRemindableActor(actorClass);
|
boolean isRemindable = ActorTypeUtilities.isRemindableActor(actorClass);
|
||||||
ActorType actorTypeAnnotation = actorClass.getAnnotation(ActorType.class);
|
|
||||||
String typeName = actorTypeAnnotation != null ? actorTypeAnnotation.name() : actorClass.getSimpleName();
|
|
||||||
|
|
||||||
|
String typeName = ActorUtils.findActorTypeName(actorClass);
|
||||||
return new ActorTypeInformation(typeName, actorClass, Arrays.asList(actorInterfaces), isAbstract, isRemindable);
|
return new ActorTypeInformation(typeName, actorClass, Arrays.asList(actorInterfaces), isAbstract, isRemindable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
package io.dapr.actors.client;
|
package io.dapr.actors.client;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
import io.dapr.serializer.DefaultObjectSerializer;
|
import io.dapr.actors.ActorType;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -14,28 +14,28 @@ public class ActorProxyBuilderTest {
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void buildWithNullActorId() {
|
public void buildWithNullActorId() {
|
||||||
new ActorProxyBuilder("test")
|
new ActorProxyBuilder("test", Object.class)
|
||||||
.build(null);
|
.build(null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void buildWithEmptyActorType() {
|
public void buildWithEmptyActorType() {
|
||||||
new ActorProxyBuilder("")
|
new ActorProxyBuilder("", Object.class)
|
||||||
.build(new ActorId("100"));
|
.build(new ActorId("100"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void buildWithNullActorType() {
|
public void buildWithNullActorType() {
|
||||||
new ActorProxyBuilder(null)
|
new ActorProxyBuilder(null, Object.class)
|
||||||
.build(new ActorId("100"));
|
.build(new ActorId("100"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void buildWithNullSerializer() {
|
public void buildWithNullSerializer() {
|
||||||
new ActorProxyBuilder("MyActor")
|
new ActorProxyBuilder("MyActor", Object.class)
|
||||||
.withObjectSerializer(null)
|
.withObjectSerializer(null)
|
||||||
.build(new ActorId("100"));
|
.build(new ActorId("100"));
|
||||||
|
|
||||||
|
@ -43,12 +43,34 @@ public class ActorProxyBuilderTest {
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
public void build() {
|
public void build() {
|
||||||
ActorProxyBuilder builder = new ActorProxyBuilder("test");
|
ActorProxyBuilder<ActorProxy> builder = new ActorProxyBuilder("test", ActorProxy.class);
|
||||||
ActorProxy actorProxy = builder.build(new ActorId("100"));
|
ActorProxy actorProxy = builder.build(new ActorId("100"));
|
||||||
|
|
||||||
Assert.assertNotNull(actorProxy);
|
Assert.assertNotNull(actorProxy);
|
||||||
Assert.assertEquals("test", actorProxy.getActorType());
|
Assert.assertEquals("test", actorProxy.getActorType());
|
||||||
Assert.assertEquals("100", actorProxy.getActorId().toString());
|
Assert.assertEquals("100", actorProxy.getActorId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
public void buildWithType() {
|
||||||
|
ActorProxyBuilder<MyActor> builder = new ActorProxyBuilder(MyActor.class);
|
||||||
|
MyActor actorProxy = builder.build(new ActorId("100"));
|
||||||
|
|
||||||
|
Assert.assertNotNull(actorProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
public void buildWithTypeDefaultName() {
|
||||||
|
ActorProxyBuilder<MyActorWithDefaultName> builder = new ActorProxyBuilder(MyActorWithDefaultName.class);
|
||||||
|
MyActorWithDefaultName actorProxy = builder.build(new ActorId("100"));
|
||||||
|
|
||||||
|
Assert.assertNotNull(actorProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ActorType(name = "MyActor")
|
||||||
|
public interface MyActor {
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyActorWithDefaultName {
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,16 +36,16 @@ public class ActorProxyImplTest {
|
||||||
public void invokeActorMethodWithoutDataWithReturnType() {
|
public void invokeActorMethodWithoutDataWithReturnType() {
|
||||||
final DaprClient daprClient = mock(DaprClient.class);
|
final DaprClient daprClient = mock(DaprClient.class);
|
||||||
Mono<byte[]> daprResponse = Mono.just(
|
Mono<byte[]> daprResponse = Mono.just(
|
||||||
"{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes());
|
"{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes());
|
||||||
|
|
||||||
when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
|
when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
|
||||||
.thenReturn(daprResponse);
|
.thenReturn(daprResponse);
|
||||||
|
|
||||||
final ActorProxy actorProxy = new ActorProxyImpl(
|
final ActorProxy actorProxy = new ActorProxyImpl(
|
||||||
"myActorType",
|
"myActorType",
|
||||||
new ActorId("100"),
|
new ActorId("100"),
|
||||||
new DefaultObjectSerializer(),
|
new DefaultObjectSerializer(),
|
||||||
daprClient);
|
daprClient);
|
||||||
|
|
||||||
Mono<MyData> result = actorProxy.invokeActorMethod("getData", MyData.class);
|
Mono<MyData> result = actorProxy.invokeActorMethod("getData", MyData.class);
|
||||||
MyData myData = result.block();
|
MyData myData = result.block();
|
||||||
|
@ -54,6 +54,27 @@ public class ActorProxyImplTest {
|
||||||
Assert.assertEquals("valueB", myData.getPropertyB());// propertyB=null
|
Assert.assertEquals("valueB", myData.getPropertyB());// propertyB=null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
public void invokeActorMethodWithoutDataWithReturnTypeViaReflection() throws NoSuchMethodException {
|
||||||
|
final DaprClient daprClient = mock(DaprClient.class);
|
||||||
|
Mono<byte[]> daprResponse = Mono.just(
|
||||||
|
"{\n\t\t\"propertyA\": \"valueA\",\n\t\t\"propertyB\": \"valueB\"\n\t}".getBytes());
|
||||||
|
|
||||||
|
when(daprClient.invokeActorMethod(anyString(), anyString(), anyString(), Mockito.isNull()))
|
||||||
|
.thenReturn(daprResponse);
|
||||||
|
|
||||||
|
final ActorProxyImpl actorProxy = new ActorProxyImpl(
|
||||||
|
"myActorType",
|
||||||
|
new ActorId("100"),
|
||||||
|
new DefaultObjectSerializer(),
|
||||||
|
daprClient);
|
||||||
|
|
||||||
|
MyData myData = (MyData) actorProxy.invoke(actorProxy, Actor.class.getMethod("getData"), null);
|
||||||
|
Assert.assertNotNull(myData);
|
||||||
|
Assert.assertEquals("valueA", myData.getPropertyA());
|
||||||
|
Assert.assertEquals("valueB", myData.getPropertyB());// propertyB=null
|
||||||
|
}
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
public void invokeActorMethodWithoutDataWithEmptyReturnType() {
|
public void invokeActorMethodWithoutDataWithEmptyReturnType() {
|
||||||
final DaprClient daprClient = mock(DaprClient.class);
|
final DaprClient daprClient = mock(DaprClient.class);
|
||||||
|
@ -250,6 +271,10 @@ public class ActorProxyImplTest {
|
||||||
Assert.assertNull(emptyResponse);
|
Assert.assertNull(emptyResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Actor {
|
||||||
|
MyData getData();
|
||||||
|
}
|
||||||
|
|
||||||
static class MyData {
|
static class MyData {
|
||||||
|
|
||||||
/// Gets or sets the value for PropertyA.
|
/// Gets or sets the value for PropertyA.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
||||||
import io.dapr.actors.client.DaprClientStub;
|
import io.dapr.actors.client.DaprClientStub;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.serializer.DefaultObjectSerializer;
|
import io.dapr.serializer.DefaultObjectSerializer;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
||||||
import io.dapr.actors.client.DaprClientStub;
|
import io.dapr.actors.client.DaprClientStub;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
||||||
import io.dapr.actors.client.DaprClientStub;
|
import io.dapr.actors.client.DaprClientStub;
|
||||||
|
@ -604,23 +605,23 @@ public class ActorStatefulTest {
|
||||||
DaprClientStub daprClient = mock(DaprClientStub.class);
|
DaprClientStub daprClient = mock(DaprClientStub.class);
|
||||||
|
|
||||||
when(daprClient.invokeActorMethod(
|
when(daprClient.invokeActorMethod(
|
||||||
eq(context.getActorTypeInformation().getName()),
|
eq(context.getActorTypeInformation().getName()),
|
||||||
eq(actorId.toString()),
|
eq(actorId.toString()),
|
||||||
any(),
|
any(),
|
||||||
any()))
|
any()))
|
||||||
.thenAnswer(invocationOnMock ->
|
.thenAnswer(invocationOnMock ->
|
||||||
this.manager.invokeMethod(
|
this.manager.invokeMethod(
|
||||||
new ActorId(invocationOnMock.getArgument(1, String.class)),
|
new ActorId(invocationOnMock.getArgument(1, String.class)),
|
||||||
invocationOnMock.getArgument(2, String.class),
|
invocationOnMock.getArgument(2, String.class),
|
||||||
invocationOnMock.getArgument(3, byte[].class)));
|
invocationOnMock.getArgument(3, byte[].class)));
|
||||||
|
|
||||||
this.manager.activateActor(actorId).block();
|
this.manager.activateActor(actorId).block();
|
||||||
|
|
||||||
return new ActorProxyForTestsImpl(
|
return new ActorProxyForTestsImpl(
|
||||||
context.getActorTypeInformation().getName(),
|
context.getActorTypeInformation().getName(),
|
||||||
actorId,
|
actorId,
|
||||||
new DefaultObjectSerializer(),
|
new DefaultObjectSerializer(),
|
||||||
daprClient);
|
daprClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createReminderParams(String data) throws IOException {
|
private byte[] createReminderParams(String data) throws IOException {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
@ -16,6 +17,13 @@ import java.time.Duration;
|
||||||
*/
|
*/
|
||||||
public class ActorTypeInformationTest {
|
public class ActorTypeInformationTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor interfaced used in this test only.
|
||||||
|
*/
|
||||||
|
@ActorType(name = "MyActorWithAnnotation")
|
||||||
|
private interface MyActorAnnotated {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actor interfaced used in this test only.
|
* Actor interfaced used in this test only.
|
||||||
*/
|
*/
|
||||||
|
@ -99,6 +107,27 @@ public class ActorTypeInformationTest {
|
||||||
Assert.assertTrue(info.getInterfaces().contains(MyActor.class));
|
Assert.assertTrue(info.getInterfaces().contains(MyActor.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks information for an actor renamed via annotation at interface.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void renamedWithAnnotationAtInterface() {
|
||||||
|
class A extends AbstractActor implements MyActorAnnotated {
|
||||||
|
A() {
|
||||||
|
super(null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorTypeInformation info = ActorTypeInformation.create(A.class);
|
||||||
|
Assert.assertNotNull(info);
|
||||||
|
Assert.assertEquals("MyActorWithAnnotation", info.getName());
|
||||||
|
Assert.assertEquals(A.class, info.getImplementationClass());
|
||||||
|
Assert.assertFalse(info.isAbstractClass());
|
||||||
|
Assert.assertFalse(info.isRemindable());
|
||||||
|
Assert.assertEquals(1, info.getInterfaces().size());
|
||||||
|
Assert.assertTrue(info.getInterfaces().contains(MyActorAnnotated.class));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks information for an actor is invalid due to an non-actor parent.
|
* Checks information for an actor is invalid due to an non-actor parent.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
||||||
import io.dapr.actors.client.DaprClientStub;
|
import io.dapr.actors.client.DaprClientStub;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package io.dapr.actors.runtime;
|
package io.dapr.actors.runtime;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
import io.dapr.actors.client.ActorProxyForTestsImpl;
|
||||||
import io.dapr.actors.client.DaprClientStub;
|
import io.dapr.actors.client.DaprClientStub;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import io.dapr.actors.ActorId;
|
||||||
import io.dapr.actors.client.ActorProxy;
|
import io.dapr.actors.client.ActorProxy;
|
||||||
import io.dapr.actors.client.ActorProxyBuilder;
|
import io.dapr.actors.client.ActorProxyBuilder;
|
||||||
import io.dapr.it.BaseIT;
|
import io.dapr.it.BaseIT;
|
||||||
|
import io.dapr.it.actors.services.springboot.DemoActor;
|
||||||
import io.dapr.it.actors.services.springboot.DemoActorService;
|
import io.dapr.it.actors.services.springboot.DemoActorService;
|
||||||
import io.dapr.it.services.EmptyService;
|
import io.dapr.it.services.EmptyService;
|
||||||
import io.dapr.serializer.DefaultObjectSerializer;
|
import io.dapr.serializer.DefaultObjectSerializer;
|
||||||
|
@ -39,30 +40,29 @@ public class ActivationDeactivationIT extends BaseIT {
|
||||||
60000);
|
60000);
|
||||||
|
|
||||||
final AtomicInteger atomicInteger = new AtomicInteger(1);
|
final AtomicInteger atomicInteger = new AtomicInteger(1);
|
||||||
String actorType = "DemoActorTest";
|
|
||||||
logger.debug("Creating proxy builder");
|
logger.debug("Creating proxy builder");
|
||||||
ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(actorType);
|
ActorProxyBuilder<DemoActor> proxyBuilder = new ActorProxyBuilder(DemoActor.class);
|
||||||
logger.debug("Creating actorId");
|
logger.debug("Creating actorId");
|
||||||
ActorId actorId1 = new ActorId(Integer.toString(atomicInteger.getAndIncrement()));
|
ActorId actorId1 = new ActorId(Integer.toString(atomicInteger.getAndIncrement()));
|
||||||
logger.debug("Building proxy");
|
logger.debug("Building proxy");
|
||||||
ActorProxy proxy = proxyBuilder.build(actorId1);
|
DemoActor proxy = proxyBuilder.build(actorId1);
|
||||||
|
|
||||||
callWithRetry(() -> {
|
callWithRetry(() -> {
|
||||||
logger.debug("Invoking Say from Proxy");
|
logger.debug("Invoking Say from Proxy");
|
||||||
String sayResponse = proxy.invokeActorMethod("say", "message", String.class).block();
|
String sayResponse = proxy.say("message");
|
||||||
logger.debug("asserting not null response: [" + sayResponse + "]");
|
logger.debug("asserting not null response: [" + sayResponse + "]");
|
||||||
assertNotNull(sayResponse);
|
assertNotNull(sayResponse);
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
logger.debug("Retrieving active Actors");
|
logger.debug("Retrieving active Actors");
|
||||||
List<String> activeActors = proxy.invokeActorMethod("retrieveActiveActors", null, List.class).block();
|
List<String> activeActors = proxy.retrieveActiveActors();
|
||||||
logger.debug("Active actors: [" + activeActors.toString() + "]");
|
logger.debug("Active actors: [" + activeActors.toString() + "]");
|
||||||
assertTrue("Expecting actorId:[" + actorId1.toString() + "]", activeActors.contains(actorId1.toString()));
|
assertTrue("Expecting actorId:[" + actorId1.toString() + "]", activeActors.contains(actorId1.toString()));
|
||||||
|
|
||||||
ActorId actorId2 = new ActorId(Integer.toString(atomicInteger.getAndIncrement()));
|
ActorId actorId2 = new ActorId(Integer.toString(atomicInteger.getAndIncrement()));
|
||||||
ActorProxy proxy2 = proxyBuilder.build(actorId2);
|
DemoActor proxy2 = proxyBuilder.build(actorId2);
|
||||||
callWithRetry(() -> {
|
callWithRetry(() -> {
|
||||||
List<String> activeActorsSecondTry = proxy2.invokeActorMethod("retrieveActiveActors", null, List.class).block();
|
List<String> activeActorsSecondTry = proxy2.retrieveActiveActors();
|
||||||
logger.debug("Active actors: [" + activeActorsSecondTry.toString() + "]");
|
logger.debug("Active actors: [" + activeActorsSecondTry.toString() + "]");
|
||||||
assertFalse("NOT Expecting actorId:[" + actorId1.toString() + "]", activeActorsSecondTry.contains(actorId1.toString()));
|
assertFalse("NOT Expecting actorId:[" + actorId1.toString() + "]", activeActorsSecondTry.contains(actorId1.toString()));
|
||||||
}, 15000);
|
}, 15000);
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class ActorStateIT extends BaseIT {
|
||||||
ActorId actorId = new ActorId(Long.toString(System.currentTimeMillis()));
|
ActorId actorId = new ActorId(Long.toString(System.currentTimeMillis()));
|
||||||
String actorType = "StatefulActorTest";
|
String actorType = "StatefulActorTest";
|
||||||
logger.debug("Building proxy ...");
|
logger.debug("Building proxy ...");
|
||||||
ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(actorType);
|
ActorProxyBuilder<ActorProxy> proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class);
|
||||||
ActorProxy proxy = proxyBuilder.build(actorId);
|
ActorProxy proxy = proxyBuilder.build(actorId);
|
||||||
|
|
||||||
callWithRetry(() -> {
|
callWithRetry(() -> {
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class ActorTurnBasedConcurrencyIT extends BaseIT {
|
||||||
String actorType="MyActorTest";
|
String actorType="MyActorTest";
|
||||||
logger.debug("Creating proxy builder");
|
logger.debug("Creating proxy builder");
|
||||||
|
|
||||||
ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(actorType);
|
ActorProxyBuilder<ActorProxy> proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class);
|
||||||
logger.debug("Creating actorId");
|
logger.debug("Creating actorId");
|
||||||
ActorId actorId1 = new ActorId(ACTOR_ID);
|
ActorId actorId1 = new ActorId(ACTOR_ID);
|
||||||
logger.debug("Building proxy");
|
logger.debug("Building proxy");
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
package io.dapr.it.actors.app;
|
package io.dapr.it.actors.app;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.runtime.AbstractActor;
|
import io.dapr.actors.runtime.AbstractActor;
|
||||||
import io.dapr.actors.runtime.ActorRuntimeContext;
|
import io.dapr.actors.runtime.ActorRuntimeContext;
|
||||||
import io.dapr.actors.runtime.ActorType;
|
|
||||||
import io.dapr.actors.runtime.Remindable;
|
import io.dapr.actors.runtime.Remindable;
|
||||||
import io.dapr.it.actors.MethodEntryTracker;
|
import io.dapr.it.actors.MethodEntryTracker;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
@ -16,7 +16,11 @@ import reactor.core.publisher.Mono;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@ActorType(name = "MyActorTest")
|
@ActorType(name = "MyActorTest")
|
||||||
public class MyActorImpl extends AbstractActor implements MyActor, Remindable<String> {
|
public class MyActorImpl extends AbstractActor implements MyActor, Remindable<String> {
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
|
|
||||||
package io.dapr.it.actors.services.springboot;
|
package io.dapr.it.actors.services.springboot;
|
||||||
|
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ActorType(name = "DemoActorTest")
|
||||||
public interface DemoActor {
|
public interface DemoActor {
|
||||||
String say(String something);
|
String say(String something);
|
||||||
|
|
||||||
|
|
|
@ -8,15 +8,16 @@ package io.dapr.it.actors.services.springboot;
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
import io.dapr.actors.runtime.AbstractActor;
|
import io.dapr.actors.runtime.AbstractActor;
|
||||||
import io.dapr.actors.runtime.ActorRuntimeContext;
|
import io.dapr.actors.runtime.ActorRuntimeContext;
|
||||||
import io.dapr.actors.runtime.ActorType;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.Duration;
|
import java.util.ArrayList;
|
||||||
import java.util.*;
|
import java.util.Calendar;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@ActorType(name = "DemoActorTest")
|
|
||||||
public class DemoActorImpl extends AbstractActor implements DemoActor {
|
public class DemoActorImpl extends AbstractActor implements DemoActor {
|
||||||
|
|
||||||
public static final List<String> ACTIVE_ACTOR = new ArrayList<>();
|
public static final List<String> ACTIVE_ACTOR = new ArrayList<>();
|
||||||
|
|
|
@ -28,8 +28,7 @@ public class DemoActorService {
|
||||||
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(2));
|
ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(2));
|
||||||
ActorRuntime.getInstance().getConfig().setDrainOngoingCallTimeout(Duration.ofSeconds(10));
|
ActorRuntime.getInstance().getConfig().setDrainOngoingCallTimeout(Duration.ofSeconds(10));
|
||||||
ActorRuntime.getInstance().getConfig().setDrainBalancedActors(true);
|
ActorRuntime.getInstance().getConfig().setDrainBalancedActors(true);
|
||||||
ActorRuntime.getInstance().registerActor(
|
ActorRuntime.getInstance().registerActor(DemoActorImpl.class);
|
||||||
DemoActorImpl.class, new DefaultObjectSerializer(), new DefaultObjectSerializer());
|
|
||||||
DaprApplication.start(port);
|
DaprApplication.start(port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
package io.dapr.it.actors.services.springboot;
|
package io.dapr.it.actors.services.springboot;
|
||||||
|
|
||||||
import io.dapr.actors.ActorId;
|
import io.dapr.actors.ActorId;
|
||||||
|
import io.dapr.actors.ActorType;
|
||||||
import io.dapr.actors.runtime.AbstractActor;
|
import io.dapr.actors.runtime.AbstractActor;
|
||||||
import io.dapr.actors.runtime.ActorRuntimeContext;
|
import io.dapr.actors.runtime.ActorRuntimeContext;
|
||||||
import io.dapr.actors.runtime.ActorType;
|
|
||||||
|
|
||||||
@ActorType(name = "StatefulActorTest")
|
@ActorType(name = "StatefulActorTest")
|
||||||
public class StatefulActorImpl extends AbstractActor implements StatefulActor {
|
public class StatefulActorImpl extends AbstractActor implements StatefulActor {
|
||||||
|
|
Loading…
Reference in New Issue