mirror of https://github.com/dapr/java-sdk.git
				
				
				
			ActorTypeInformation with parsing logic + some stubs.
This commit is contained in:
		
							parent
							
								
									937224e2f3
								
							
						
					
					
						commit
						9dd68c8f71
					
				| 
						 | 
				
			
			@ -171,6 +171,7 @@ class DaprHttpAsyncClient implements DaprAsyncClient {
 | 
			
		|||
                .addHeader(Constants.HEADER_DAPR_REQUEST_ID, requestId)
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        // TODO: make this call async as well.
 | 
			
		||||
        Response response = this.httpClient.newCall(request).execute();
 | 
			
		||||
        if (!response.isSuccessful())
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractActor {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO
 | 
			
		||||
 */
 | 
			
		||||
public interface Actor {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
import java.lang.annotation.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Annotation to override default behavior of Actor class.
 | 
			
		||||
 */
 | 
			
		||||
@Documented
 | 
			
		||||
@Target(ElementType.TYPE_USE)
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
public @interface ActorType {
 | 
			
		||||
 | 
			
		||||
    String Name();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,181 @@
 | 
			
		|||
/*
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 2019 Swen Schisler <swen.schisler@fourtytwosoft.io>.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Modifier;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains the information about the class implementing an actor.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Swen Schisler <swen.schisler@fourtytwosoft.io>
 | 
			
		||||
 * @author Artur Souza <artur.barbalho@microsoft.com>
 | 
			
		||||
 */
 | 
			
		||||
public final class ActorTypeInformation {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Actor type's name.
 | 
			
		||||
     */
 | 
			
		||||
    private final String name;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Actor's implementation class.
 | 
			
		||||
     */
 | 
			
		||||
    private final Class implementationClass;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Actor's immediate interfaces.
 | 
			
		||||
     */
 | 
			
		||||
    private final Collection<Class> interfaces;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether Actor type is abstract.
 | 
			
		||||
     */
 | 
			
		||||
    private final boolean abstractClass;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether Actor type is remindable.
 | 
			
		||||
     */
 | 
			
		||||
    private final boolean remindable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new {@link ActorTypeInformation}
 | 
			
		||||
     * @param name Actor type's name.
 | 
			
		||||
     * @param implementationClass Actor's implementation class.
 | 
			
		||||
     * @param interfaces Actor's immediate interfaces.
 | 
			
		||||
     * @param abstractClass Whether Actor type is abstract.
 | 
			
		||||
     * @param remindable Whether Actor type is remindable.
 | 
			
		||||
     */
 | 
			
		||||
    private ActorTypeInformation(String name,
 | 
			
		||||
                                 Class implementationClass,
 | 
			
		||||
                                 Collection<Class> interfaces,
 | 
			
		||||
                                 boolean abstractClass,
 | 
			
		||||
                                 boolean remindable) {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.implementationClass = implementationClass;
 | 
			
		||||
        this.interfaces = interfaces;
 | 
			
		||||
        this.abstractClass = abstractClass;
 | 
			
		||||
        this.remindable = remindable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the name of this ActorType.
 | 
			
		||||
     * @return ActorType's name.
 | 
			
		||||
     */
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return this.name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the type of the class implementing the actor.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The {@link Class} of implementing the actor.
 | 
			
		||||
     */
 | 
			
		||||
    public Class getImplementationClass() {
 | 
			
		||||
        return this.implementationClass;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the actor interfaces which derive from {@link Actor} and implemented by actor class.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Collection of actor interfaces.
 | 
			
		||||
     */
 | 
			
		||||
    public Collection<Class> getInterfaces() {
 | 
			
		||||
        return Collections.unmodifiableCollection(this.interfaces);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a value indicating whether the class implementing actor is abstract.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if the class implementing actor is abstract, otherwise false.
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isAbstractClass() {
 | 
			
		||||
        return this.abstractClass;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a value indicating whether the actor class implements {@link Remindable}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return true if the actor class implements {@link Remindable}.
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isRemindable() {
 | 
			
		||||
        return this.remindable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the {@link ActorTypeInformation} from given Class.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actorClass The type of class implementing the actor to create ActorTypeInformation for.
 | 
			
		||||
     * @return ActorTypeInformation if successfully created for actorType or null.
 | 
			
		||||
     */
 | 
			
		||||
    public static ActorTypeInformation tryCreate(Class actorClass) {
 | 
			
		||||
        try {
 | 
			
		||||
            return create(actorClass);
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an {@link #ActorTypeInformation} from actorType.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actorClass The class implementing the actor to create ActorTypeInformation for.
 | 
			
		||||
     * @return {@link #ActorTypeInformation} created from actorType.
 | 
			
		||||
     */
 | 
			
		||||
    public static ActorTypeInformation create(Class actorClass) {
 | 
			
		||||
        if (!ActorTypeUtilities.isActor(actorClass)) {
 | 
			
		||||
            throw new IllegalArgumentException(
 | 
			
		||||
                    String.format(
 | 
			
		||||
                            "The type '%s' is not an Actor. An actor type must derive from '%s'.",
 | 
			
		||||
                            actorClass == null ? "" : actorClass.getCanonicalName(),
 | 
			
		||||
                            Actor.class.getCanonicalName()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // get all actor interfaces
 | 
			
		||||
        Class<?>[] actorInterfaces = actorClass.getInterfaces();
 | 
			
		||||
 | 
			
		||||
        boolean isAbstract = Modifier.isAbstract(actorClass.getModifiers());
 | 
			
		||||
        // ensure that the if the actor type is not abstract it implements at least one actor interface
 | 
			
		||||
        if ((actorInterfaces.length == 0) && !isAbstract) {
 | 
			
		||||
            throw new IllegalArgumentException(
 | 
			
		||||
                    String.format(
 | 
			
		||||
                            "The actor type '%s' does not implement any actor interfaces or one of the " +
 | 
			
		||||
                                    "interfaces implemented is not an actor interface. " +
 | 
			
		||||
                                    "All interfaces(including its parent interface) implemented by actor type must " +
 | 
			
		||||
                                    "be actor interface. An actor interface is the one that ultimately derives " +
 | 
			
		||||
                                    "from '%s' type.",
 | 
			
		||||
                            actorClass == null ? "" : actorClass.getCanonicalName(),
 | 
			
		||||
                            Actor.class.getCanonicalName()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        boolean isRemindable = ActorTypeUtilities.isRemindableActor(actorClass);
 | 
			
		||||
        ActorType actorTypeAnnotation = (ActorType) actorClass.getAnnotation(ActorType.class);
 | 
			
		||||
        String typeName = actorTypeAnnotation != null ? actorTypeAnnotation.Name() : actorClass.getSimpleName();
 | 
			
		||||
 | 
			
		||||
        return new ActorTypeInformation(typeName, actorClass, Arrays.asList(actorInterfaces), isAbstract, isRemindable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Utility class to extract information on Actor type.
 | 
			
		||||
 */
 | 
			
		||||
final class ActorTypeUtilities {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all interfaces that extend Actor.
 | 
			
		||||
     * @param clazz Actor class.
 | 
			
		||||
     * @return Array of Actor interfaces.
 | 
			
		||||
     */
 | 
			
		||||
    public static Class[] getActorInterfaces(Class clazz) {
 | 
			
		||||
        if (clazz == null) {
 | 
			
		||||
            return new Class[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return Arrays.stream(clazz.getInterfaces())
 | 
			
		||||
                .filter(t -> Actor.class.isAssignableFrom(t))
 | 
			
		||||
                .filter(t -> getNonActorParentClass(t) == null)
 | 
			
		||||
                .toArray(Class[]::new);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines if given class is an Actor interface.
 | 
			
		||||
     * @param clazz Actor interface candidate.
 | 
			
		||||
     * @return Whether this is an Actor interface.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isActorInterface(Class clazz) {
 | 
			
		||||
        return (clazz != null) && clazz.isInterface() && (getNonActorParentClass(clazz) == null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines whether this is an Actor class.
 | 
			
		||||
     * @param clazz Actor class candidate.
 | 
			
		||||
     * @return Whether this is an Actor class.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isActor(Class clazz) {
 | 
			
		||||
        if (clazz == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AbstractActor.class.isAssignableFrom(clazz);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Determines whether this is an remindable Actor.
 | 
			
		||||
     * @param clazz Actor class.
 | 
			
		||||
     * @return Whether this is an remindable Actor.
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean isRemindableActor(Class clazz) {
 | 
			
		||||
        return (clazz != null) && isActor(clazz) && (Arrays.stream(clazz.getInterfaces()).filter(t -> t.equals(Remindable.class)).count() > 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the parent class if it is not the {@link AbstractActor} parent class.
 | 
			
		||||
     * @param clazz Actor class.
 | 
			
		||||
     * @return Parent class or null if it is {@link AbstractActor}.
 | 
			
		||||
     */
 | 
			
		||||
    public static Class getNonActorParentClass(Class clazz) {
 | 
			
		||||
        if (clazz == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Class[] items = Arrays.stream(clazz.getInterfaces()).filter(t -> !t.equals(Actor.class)).toArray(Class[]::new);
 | 
			
		||||
        if (items.length == 0) {
 | 
			
		||||
            return clazz;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Class c : items) {
 | 
			
		||||
            Class nonActorParent = getNonActorParentClass(c);
 | 
			
		||||
            if (nonActorParent != null) {
 | 
			
		||||
                return nonActorParent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO
 | 
			
		||||
 */
 | 
			
		||||
public interface Remindable {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Licensed under the MIT License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package io.dapr.actors.runtime;
 | 
			
		||||
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unit tests for ActorTypeInformation.
 | 
			
		||||
 */
 | 
			
		||||
public class ActorTypeInformationTest {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Actor interfaced used in this test only.
 | 
			
		||||
     */
 | 
			
		||||
    private interface MyActor extends Actor {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks information for a non-remindable actor.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void notRemindable() {
 | 
			
		||||
 | 
			
		||||
        class A extends AbstractActor implements MyActor {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ActorTypeInformation info = ActorTypeInformation.create(A.class);
 | 
			
		||||
        Assert.assertNotNull(info);
 | 
			
		||||
        Assert.assertEquals("A", 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(MyActor.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks information for a remindable actor.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void remindable() {
 | 
			
		||||
 | 
			
		||||
        class A extends AbstractActor implements MyActor, Remindable {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ActorTypeInformation info = ActorTypeInformation.create(A.class);
 | 
			
		||||
        Assert.assertNotNull(info);
 | 
			
		||||
        Assert.assertEquals("A", info.getName());
 | 
			
		||||
        Assert.assertEquals(A.class, info.getImplementationClass());
 | 
			
		||||
        Assert.assertFalse(info.isAbstractClass());
 | 
			
		||||
        Assert.assertTrue(info.isRemindable());
 | 
			
		||||
        Assert.assertEquals(2, info.getInterfaces().size());
 | 
			
		||||
        Assert.assertTrue(info.getInterfaces().contains(Remindable.class));
 | 
			
		||||
        Assert.assertTrue(info.getInterfaces().contains(MyActor.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks information for an actor renamed via annotation.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void renamedWithAnnotation() {
 | 
			
		||||
        @ActorType(Name = "B")
 | 
			
		||||
        class A extends AbstractActor implements MyActor {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ActorTypeInformation info = ActorTypeInformation.create(A.class);
 | 
			
		||||
        Assert.assertNotNull(info);
 | 
			
		||||
        Assert.assertEquals("B", 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(MyActor.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks information for an actor is invalid due to an non-actor parent.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void nonActorParentClass() {
 | 
			
		||||
        abstract class MyAbstractClass extends AbstractActor implements MyActor {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        class A extends MyAbstractClass {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ActorTypeInformation info = ActorTypeInformation.tryCreate(A.class);
 | 
			
		||||
        Assert.assertNull(info);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue