package org.scribble.codegen.java.endpointapi; import org.scribble.ast.DataTypeDecl; import org.scribble.ast.MessageSigNameDecl; import org.scribble.ast.NonProtocolDecl; import org.scribble.ast.global.GProtocolDecl; 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.JavaBuilder; import org.scribble.codegen.java.util.MethodBuilder; import org.scribble.main.ScribbleException; import org.scribble.model.endpoint.EState; import org.scribble.sesstype.name.GProtocolName; import org.scribble.sesstype.name.MessageId; import org.scribble.sesstype.name.Role; // Parameterize on output class type public abstract class ScribSocketGenerator extends StateChannelTypeGenerator { public static final String JAVA_SCHEMA = "java"; // FIXME: factor out public static final String SESSIONENDPOINT_CLASS = "org.scribble.net.session.SessionEndpoint"; public static final String MPSTENDPOINT_CLASS = "org.scribble.net.session.MPSTEndpoint"; public static final String EXPLICITENDPOINT_CLASS = "org.scribble.net.session.ExplicitEndpoint"; public static final String BUF_CLASS = "org.scribble.net.Buf"; public static final String OPENUM_INTERFACE = "org.scribble.net.session.OpEnum"; //public static final String CONNECTSOCKET_CLASS = "org.scribble.net.scribsock.ConnectSocket"; public static final String ACCEPTSOCKET_CLASS = "org.scribble.net.scribsock.AcceptSocket"; //public static final String DISCONNECTSOCKET_CLASS = "org.scribble.net.scribsock.DisconnectSocket"; public static final String OUTPUTSOCKET_CLASS = "org.scribble.net.scribsock.OutputSocket"; public static final String RECEIVESOCKET_CLASS = "org.scribble.net.scribsock.ReceiveSocket"; public static final String BRANCHSOCKET_CLASS = "org.scribble.net.scribsock.BranchSocket"; public static final String CASESOCKET_CLASS = "org.scribble.net.scribsock.CaseSocket"; public static final String ENDSOCKET_CLASS = "org.scribble.net.scribsock.EndSocket"; public static final String SCRIBSERVERSOCKET_CLASS = "org.scribble.net.scribsock.ScribServerSocket"; public static final String GENERATED_ENDSOCKET_NAME = "EndSocket"; public static final String BUFF_VAL_FIELD = "val"; public static final String SCRIBSOCKET_SE_FIELD = JavaBuilder.THIS + ".se"; public static final String SCRIBMESSAGE_PAYLOAD_FIELD = "payload"; public static final String RECEIVE_MESSAGE_PARAM = "m"; public static final String RECEIVE_ARG_PREFIX = "arg"; public static final String CASE_OP_FIELD = "op"; public static final String CASE_OP_PARAM = CASE_OP_FIELD; public static final String CASE_MESSAGE_FIELD = "m"; public static final String CASE_MESSAGE_PARAM = CASE_MESSAGE_FIELD; public static final String CASE_ARG_PREFIX = "arg"; protected final EState curr; protected final String className; protected final ClassBuilder cb = new ClassBuilder(); public ScribSocketGenerator(StateChannelApiGenerator apigen, EState curr) { super(apigen); this.curr = curr; this.className = getClassName(); } protected String getClassName() { return this.apigen.getSocketClassName(this.curr); } @Override public ClassBuilder generateType() throws ScribbleException { constructClass(); // So className can be "overridden" in subclass constructor (CaseSocket) return this.cb; } protected void constructClass() throws ScribbleException { constructClassExceptMethods(); addMethods(); } protected void constructClassExceptMethods() { this.cb.setName(this.className); //this.cb.setPackage(getSessionPackageName()); this.cb.setPackage(getStateChannelPackageName()); this.cb.addModifiers(JavaBuilder.PUBLIC, JavaBuilder.FINAL); //cb.setSuperClass(superc + "<" + SessionApiGenerator.getSessionClassName(this.gpn) + ", " + SessionApiGenerator.getRoleClassName(this.self) + ">"); this.cb.setSuperClass(getSuperClassType()); addImports(); addConstructor(); FieldBuilder cast = this.cb.newField("cast"); cast.addModifiers(JavaBuilder.PUBLIC, JavaBuilder.STATIC, JavaBuilder.FINAL); cast.setType(this.className); cast.setExpression("null"); } protected abstract String getSuperClassType(); protected void addImports() { //this.cb.addImports("java.io.IOException"); //this.cb.addImports(getSessionPackageName() + "." + getSessionClassName()); this.cb.addImports(getEndpointApiRootPackageName() + ".*"); this.cb.addImports(getRolesPackageName() + ".*"); } protected MethodBuilder addConstructor() { final String SESSIONENDPOINT_PARAM = "se"; final String sess = getSessionClassName(); final String role = getSelfClassName(); ConstructorBuilder ctor = cb.newConstructor(SESSIONENDPOINT_CLASS + "<" + sess + ", " + role + "> " + SESSIONENDPOINT_PARAM, "boolean dummy"); ctor.addModifiers(JavaBuilder.PROTECTED); ctor.addBodyLine(JavaBuilder.SUPER + "(" + SESSIONENDPOINT_PARAM + ");"); if (this.curr.equals(this.apigen.getInitialState())) { addInitialStateConstructor(); } return ctor; } protected void addInitialStateConstructor() { final String SESSIONENDPOINT_PARAM = "se"; String sess = getSessionClassName(); String role = getSelfClassName(); /*MethodBuilder mb = cb.newMethod("init"); mb.addModifiers(ClassBuilder.PUBLIC, ClassBuilder.STATIC); mb.setReturn(this.root); mb.addParameters(SESSIONENDPOINT_CLASS + "<" + role + "> " + SESSIONENDPOINT_PARAM); mb.addExceptions(SCRIBBLERUNTIMEEXCEPTION_CLASS); mb.addBodyLine(SESSIONENDPOINT_PARAM + ".init();"); mb.addBodyLine(ClassBuilder.RETURN + " " + ClassBuilder.NEW + " " + this.root + "(" + SESSIONENDPOINT_PARAM + ");");*/ GProtocolDecl gpd = (GProtocolDecl) this.apigen.getJob().getContext().getModule(this.apigen.gpn.getPrefix()).getProtocolDecl(this.apigen.gpn.getSimpleName()); String epClass = gpd.isExplicitModifier() ? EXPLICITENDPOINT_CLASS : MPSTENDPOINT_CLASS; ConstructorBuilder ctor2 = cb.newConstructor(epClass + "<" + sess + ", " + role + "> " + SESSIONENDPOINT_PARAM); ctor2.addExceptions(StateChannelApiGenerator.SCRIBBLERUNTIMEEXCEPTION_CLASS); ctor2.addModifiers(JavaBuilder.PUBLIC); ctor2.addBodyLine(JavaBuilder.SUPER + "(" + SESSIONENDPOINT_PARAM + ");"); ctor2.addBodyLine(SESSIONENDPOINT_PARAM + ".init();"); } protected abstract void addMethods() throws ScribbleException; /*@Deprecated protected void setNextSocketReturnType(MethodBuilder mb, EState succ) { setNextSocketReturnType(this.apigen, mb, succ); }*/ //protected void addReturnNextSocket(MethodBuilder mb, String nextClass) protected void addReturnNextSocket(MethodBuilder mb, EState s) { String nextClass; //if (isTerminalClassName(nextClass)) if (s.isTerminal()) { mb.addBodyLine(SCRIBSOCKET_SE_FIELD + ".setCompleted();"); // Do before the IO action? in case of exception? nextClass = GENERATED_ENDSOCKET_NAME;// + "<>"; } else { nextClass = this.apigen.getSocketClassName(s); } mb.addBodyLine(JavaBuilder.RETURN + " " + JavaBuilder.NEW + " " + nextClass + "(" + SCRIBSOCKET_SE_FIELD + ", true);"); } protected String getGarbageBuf(String futureClass) { //return ClassBuilder.NEW + " " + BUFF_CLASS + "<>()"; // Makes a trash Buff every time, but clean -- would be more efficient to generate the code to spawn the future without buff-ing it (partly duplicate of the normal receive generated code) return "(" + BUF_CLASS + "<" + futureClass + ">) " + SCRIBSOCKET_SE_FIELD + ".gc"; // FIXME: generic cast warning (this.ep.gc is Buff<?>) -- also retains unnecessary reference to the last created garbage future (but allows no-arg receive/async to be generated as simple wrapper call) } // Not fully qualified, just Session API class prefix // The constant singleton value of this type in the Session API (which is the same "name" as the class) protected String getSessionApiRoleConstant(Role role) { return SessionApiGenerator.getSessionClassName(this.apigen.getGProtocolName()) + "." + role; } // Not fully qualified, just Session API class prefix // The constant singleton value of this type in the Session API (which is the same "name" as the class) protected String getSessionApiOpConstant(MessageId<?> mid) { return SessionApiGenerator.getSessionClassName(this.apigen.getGProtocolName()) + "." + SessionApiGenerator.getOpClassName(mid); } // Wrappers for EndpointApiGenerator getters protected String getSessionClassName() { return SessionApiGenerator.getSessionClassName(this.apigen.getGProtocolName()); } protected String getSelfClassName() { return SessionApiGenerator.getRoleClassName(this.apigen.getSelf()); } protected String getEndpointApiRootPackageName() { /*GProtocolName gpn = this.apigen.getGProtocolName(); return SessionApiGenerator.getSessionApiPackageName(this.apigen.getGProtocolName()) + ".api" + gpn.getSimpleName();*/ return SessionApiGenerator.getEndpointApiRootPackageName(this.apigen.getGProtocolName()); } protected String getRolesPackageName() { return SessionApiGenerator.getRolesPackageName(this.apigen.getGProtocolName()); } protected String getOpsPackageName() { return SessionApiGenerator.getOpsPackageName(this.apigen.getGProtocolName()); } protected String getStateChannelPackageName() { //return getSessionPackageName() + ".channels." + this.apigen.getSelf(); return SessionApiGenerator.getStateChannelPackageName(this.apigen.getGProtocolName(), this.apigen.getSelf()); } public static void setNextSocketReturnType(StateChannelApiGenerator apigen, MethodBuilder mb, EState succ) { String ret; if (succ.isTerminal()) { GProtocolName gpn = apigen.getGProtocolName(); Role self = apigen.getSelf(); ret = SessionApiGenerator.getStateChannelPackageName(gpn, self) + "." + GENERATED_ENDSOCKET_NAME; //+ "<" + SessionApiGenerator.getSessionClassName(gpn) + ", " + SessionApiGenerator.getRoleClassName(self) + ">"; } else { ret = apigen.getSocketClassName(succ); } mb.setReturn(ret); } protected static void checkJavaDataTypeDecl(DataTypeDecl dtd) throws ScribbleException { checkJavaSchema(dtd); } protected static void checkMessageSigNameDecl(MessageSigNameDecl msd) throws ScribbleException { checkJavaSchema(msd); } protected static void checkJavaSchema(NonProtocolDecl<?> npd) throws ScribbleException { if (!npd.schema.equals(ScribSocketGenerator.JAVA_SCHEMA)) // FIXME: factor out { throw new ScribbleException(npd.getSource(), "Unsupported data type schema: " + npd.schema); } } /*private static boolean isTerminalClassName(String n) { //return n.equals(ClassBuilder.VOID); return n.equals(EndpointApiGenerator.ENDSOCKET_CLASS); }*/ /*// Pre: not a terminal state (i.e. className is not void) private ClassBuilder constructInitClass(String className) { final String SESSIONENDPOINT_PARAM = "se"; String role = SessionApiGenerator.getRoleClassName(this.self); ClassBuilder cb = new ClassBuilder(); cb.setName(className); cb.setPackage(getPackageName()); cb.setSuperClass(INITSOCKET_CLASS + "<" + role + ">"); cb.addModifiers(ClassBuilder.PUBLIC); MethodBuilder ctor = cb.newConstructor(SESSIONENDPOINT_CLASS + "<" + role + "> " + SESSIONENDPOINT_PARAM); ctor.addModifiers(ClassBuilder.PUBLIC); ctor.addBodyLine(ClassBuilder.SUPER + "(" + SESSIONENDPOINT_PARAM + ");"); MethodBuilder mb = cb.newMethod("init"); mb.setReturn(this.root); mb.addModifiers(ClassBuilder.PUBLIC); mb.addExceptions(SCRIBBLERUNTIMEEXCEPTION_CLASS); mb.addBodyLine(ClassBuilder.SUPER + ".use();"); // Factor out //mb.addBodyLine(SCRIBSOCKET_SE_FIELD + ".init();"); // Factor out addReturnNextSocket(mb, this.root); return cb; }*/ }