[java] support creating an actor with parameters (#2817)

Previously `Ray.createActor` only support creating an actor without any parameter. This PR adds the support for creating an actor with parameters. Moreover, besides using a constructor, it's now also allowed to create an actor with a factory method. For more usage, prefer refer to `ActorTest.java`.
This commit is contained in:
Hao Chen
2018-09-04 00:53:03 +08:00
committed by Robert Nishihara
parent b37a283053
commit 9d655721e5
27 changed files with 1131 additions and 680 deletions
@@ -4,6 +4,8 @@ import com.google.common.base.Preconditions;
import java.io.Serializable;
import java.lang.invoke.MethodHandleInfo;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
@@ -67,13 +69,15 @@ public final class MethodId {
return sb.toString();
}
public static MethodId fromMethod(Method method) {
final boolean isstatic = Modifier.isStatic(method.getModifiers());
public static MethodId fromExecutable(Executable method) {
final boolean isStatic = Modifier.isStatic(method.getModifiers());
final String className = method.getDeclaringClass().getName();
final String methodName = method.getName();
final Type type = Type.getType(method);
final String methodName = method instanceof Method
? method.getName() : "<init>";
final Type type = method instanceof Method
? Type.getType((Method) method) : Type.getType((Constructor) method);
final String methodDesc = type.getDescriptor();
return new MethodId(className, methodName, methodDesc, isstatic);
return new MethodId(className, methodName, methodDesc, isStatic);
}
public static MethodId fromSerializedLambda(Serializable serial) {
@@ -101,7 +105,6 @@ public final class MethodId {
return id;
}
public Method load() {
return load(null);
}
@@ -2,6 +2,7 @@ package org.ray.util;
import java.util.HashMap;
import java.util.Map;
import org.ray.api.annotation.RayRemote;
import org.ray.api.annotation.ResourceItem;
public class ResourceUtil {
@@ -11,17 +12,18 @@ public class ResourceUtil {
/**
* Convert the array that contains resource items to a map.
*
* @param resourceArray The resources list to be converted.
* @param remoteAnnotation The RayRemote annotation that contains the resource items.
* @return The map whose key represents the resource name
* and the value represents the resource quantity.
*/
public static Map<String, Double> getResourcesMapFromArray(ResourceItem[] resourceArray) {
public static Map<String, Double> getResourcesMapFromArray(RayRemote remoteAnnotation) {
Map<String, Double> resourceMap = new HashMap<>();
if (resourceArray != null) {
for (ResourceItem item : resourceArray) {
if (!item.name().isEmpty()) {
resourceMap.put(item.name(), item.value());
}
if (remoteAnnotation == null) {
return resourceMap;
}
for (ResourceItem item : remoteAnnotation.resources()) {
if (!item.name().isEmpty()) {
resourceMap.put(item.name(), item.value());
}
}
@@ -10,6 +10,11 @@ public abstract class BaseGenerator {
sb.append(line).append("\n");
}
protected void newLine(int numIndents, String line) {
indents(numIndents);
newLine(line);
}
protected void indents(int numIndents) {
for (int i = 0; i < numIndents; i++) {
sb.append(" ");
@@ -6,7 +6,8 @@ import java.util.List;
import org.ray.util.FileUtil;
/**
* A util class that generates `RayCall.java`
* A util class that generates `RayCall.java`,
* which provides type-safe interfaces for `Ray.call` and `Ray.createActor`.
*/
public class RayCallGenerator extends BaseGenerator {
@@ -24,64 +25,76 @@ public class RayCallGenerator extends BaseGenerator {
newLine("");
newLine("/**");
newLine(" * This class provides type-safe interfaces for Ray.call.");
newLine(" * This class provides type-safe interfaces for `Ray.call` and `Ray.createActor`.");
newLine(" **/");
newLine("@SuppressWarnings({\"rawtypes\", \"unchecked\"})");
newLine("class RayCall {");
for (int i = 0; i <= 6; i++) {
if (i > 0) {
buildCalls(i, true);
}
buildCalls(i, false);
newLine(1, "// =======================================");
newLine(1, "// Methods for remote function invocation.");
newLine(1, "// =======================================");
for (int i = 0; i <= MAX_PARAMETERS; i++) {
buildCalls(i, false, false);
}
newLine(1, "// ===========================================");
newLine(1, "// Methods for remote actor method invocation.");
newLine(1, "// ===========================================");
for (int i = 0; i <= MAX_PARAMETERS - 1; i++) {
buildCalls(i, true, false);
}
newLine(1, "// ===========================");
newLine(1, "// Methods for actor creation.");
newLine(1, "// ===========================");
for (int i = 0; i <= MAX_PARAMETERS; i++) {
buildCalls(i, false, true);
}
newLine("}");
return sb.toString();
}
/**
* Build the `Ray.call` methods for given number of parameters.
* @param numParameters the number of parameters, including the actor parameter.
* Build the `Ray.call` or `Ray.createActor` methods with the given number of parameters.
* @param numParameters the number of parameters
* @param forActor build actor api when true, otherwise build task api.
* @param forActorCreation build `Ray.createActor` when true, otherwise build `Ray.call`.
*/
private void buildCalls(int numParameters, boolean forActor) {
private void buildCalls(int numParameters, boolean forActor, boolean forActorCreation) {
String genericTypes = "";
String argList = "";
for (int i = 0; i < numParameters; i++) {
genericTypes += "T" + i + ", ";
if (!forActor || i > 0) {
argList += "t" + i + ", ";
}
argList += "t" + i + ", ";
}
if (forActor) {
genericTypes = "A, " + genericTypes;
}
genericTypes += forActorCreation ? "A" : "R";
if (argList.endsWith(", ")) {
argList = argList.substring(0, argList.length() - 2);
}
String funcParam = String.format("RayFunc%d<%sR> f%s",
numParameters,
genericTypes,
numParameters > 0 ? ", " : "");
String actorParam = "";
String paramPrefix = String.format("RayFunc%d<%s> f",
!forActor ? numParameters : numParameters + 1,
genericTypes);
if (forActor) {
actorParam = "RayActor<T0> actor";
if (numParameters > 1) {
actorParam += ", ";
}
paramPrefix += ", RayActor<A> actor";
}
if (numParameters > 0) {
paramPrefix += ", ";
}
for (String param : generateParameters(forActor ? 1 : 0, numParameters)) {
String returnType = !forActorCreation ? "RayObject<R>" : "RayActor<A>";
String funcName = !forActorCreation ? "call" : "createActor";
String funcArgs = !forActor ? "f, args" : "f, actor, args";
for (String param : generateParameters(0, numParameters)) {
// method signature
indents(1);
newLine(String.format(
"public static <%sR> RayObject<R> call(%s%s%s) {",
genericTypes, funcParam, actorParam, param
newLine(1, String.format(
"public static <%s> %s %s(%s) {",
genericTypes, returnType, funcName, paramPrefix + param
));
// method body
indents(2);
newLine(String.format("Object[] args = new Object[]{%s};", argList));
indents(2);
newLine(String.format("return Ray.internal().call(f%s, args);", forActor ? ", actor" : ""));
indents(1);
newLine("}");
newLine(2, String.format("Object[] args = new Object[]{%s};", argList));
newLine(2, String.format("return Ray.internal().%s(%s);", funcName, funcArgs));
newLine(1, "}");
}
}