package org.scribble.codegen.java.endpointapi;
import java.util.LinkedList;
import java.util.List;
import org.scribble.ast.DataTypeDecl;
import org.scribble.ast.MessageSigNameDecl;
import org.scribble.ast.Module;
import org.scribble.codegen.java.util.ClassBuilder;
import org.scribble.codegen.java.util.ConstructorBuilder;
import org.scribble.codegen.java.util.FieldBuilder;
import org.scribble.codegen.java.util.InterfaceBuilder;
import org.scribble.codegen.java.util.JavaBuilder;
import org.scribble.codegen.java.util.MethodBuilder;
import org.scribble.main.ScribbleException;
import org.scribble.model.endpoint.actions.EAction;
import org.scribble.sesstype.name.DataType;
import org.scribble.sesstype.name.GProtocolName;
import org.scribble.sesstype.name.MessageSigName;
import org.scribble.sesstype.name.PayloadType;
public class InputFutureGenerator extends AuxStateChannelTypeGenerator
{
protected static final String SCRIBFUTURE_CLASS = "org.scribble.net.ScribFuture";
private final EAction a;
// Pre: cb is ReceiveSocketBuilder
public InputFutureGenerator(StateChannelApiGenerator apigen, ClassBuilder parent, EAction a)
{
super(apigen, parent);
this.a = a;
}
@Override
public ClassBuilder generateType() throws ScribbleException
{
final String FUTURE_PARAM = "fut";
Module main = this.apigen.getMainModule();
GProtocolName gpn = this.apigen.getGProtocolName();
String futureClass = getInputFutureName(this.parent.getName()); // Fresh enough? need only one future class per receive (unary receive)
//cb.addImports("java.util.concurrent.CompletableFuture"); // "parent" cb, not the future class
//cb.addImports("java.util.concurrent.ExecutionException");
//ClassBuilder future = cb.newClass(); // FIXME: inner class
// Duplicated from BranchInterfaceBuilder -- FIXME: factor out
ClassBuilder future = new ClassBuilder();
future.setPackage(SessionApiGenerator.getStateChannelPackageName(gpn, this.apigen.getSelf())); // FIXME: factor out with ScribSocketBuilder
future.addImports("java.io.IOException");
future.addImports("java.util.concurrent.CompletableFuture"); // "parent" cb, not the future class
future.addModifiers(InterfaceBuilder.PUBLIC);
future.setName(futureClass);
future.setSuperClass(SCRIBFUTURE_CLASS);
List<String> types = new LinkedList<>();
if (a.mid.isOp())
{
if (!a.payload.isEmpty())
{
int i = 1;
for (PayloadType<?> pt : a.payload.elems)
{
if (!pt.isDataType())
{
throw new ScribbleException("[TODO] API generation not supported for non- data type payloads: " + pt);
}
DataTypeDecl dtd = main.getDataTypeDecl((DataType) pt);
ScribSocketGenerator.checkJavaDataTypeDecl(dtd);
String type = dtd.extName;
types.add(type);
FieldBuilder f = future.newField("pay" + i++);
f.setType(type);
f.addModifiers(JavaBuilder.PUBLIC);
}
}
}
else
{
MessageSigNameDecl msd = main.getMessageSigDecl(((MessageSigName) a.mid).getSimpleName());
ScribSocketGenerator.checkMessageSigNameDecl(msd);
String type = msd.extName;
types.add(type);
FieldBuilder f = future.newField("msg");
f.setType(type);
f.addModifiers(JavaBuilder.PUBLIC);
}
ConstructorBuilder cons = future.newConstructor("CompletableFuture<" + StateChannelApiGenerator.SCRIBMESSAGE_CLASS + "> " + FUTURE_PARAM);
cons.addModifiers(JavaBuilder.PROTECTED);
cons.addBodyLine(JavaBuilder.SUPER + "(" + FUTURE_PARAM + ");");
MethodBuilder sync = future.newMethod("sync");
sync.addModifiers(JavaBuilder.PUBLIC);
sync.setReturn(futureClass);
//sync.addExceptions("ExecutionException", "InterruptedException");
sync.addExceptions("IOException");
String ln = (a.mid.isOp() && a.payload.isEmpty()) ? "" : StateChannelApiGenerator.SCRIBMESSAGE_CLASS + " m = ";
ln += JavaBuilder.SUPER + ".get();";
sync.addBodyLine(ln);
if (a.mid.isOp())
{
if (!a.payload.isEmpty())
{
int i = 1;
for (String type : types)
{
sync.addBodyLine(JavaBuilder.THIS + "." + "pay" + i + " = (" + type + ") m.payload[" + (i - 1) + "];");
i++;
}
}
}
else
{
sync.addBodyLine(JavaBuilder.THIS + "." + "msg" + " = (" + types.get(0) + ") m;");
}
sync.addBodyLine(JavaBuilder.RETURN + " " + JavaBuilder.THIS + ";");
return future;
}
public static String getInputFutureName(String parent)
{
return parent + "_Future"; // Fresh enough? need only one future class per receive (unary receive)
}
}