mirror of https://github.com/dapr/java-sdk.git
				
				
				
			Merge pull request #41 from artursouza/actors
ActorTypeInformation with parsing logic + some stubs.
This commit is contained in:
		
						commit
						6584744b2f
					
				|  | @ -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