
// RPCServer.java
// Andrew Davison, ad@coe.psu.ac.th, May 2023

/* A client/server example where the server executes RPCs
   sent by a client.

   Each RPC is represented by two tuples of the form:
      (callerID, "func", functionName);    
      (callerID, "args", <series of function arguments>);
   e.g.
      ("Alice1", "func", "add3")  
      ("Alice1", "args", 1, 2, 3)
   represents the function call: add3(1,2,3)

   The server replies with a single tuple of the form:
      (callerID, "result", ObjectResult)

   Explained in section 3.7 at:
    https://github.com/pSpaces/Programming-with-Spaces/blob/master/tutorial-distributed-programming.md

   Usage:
    > compile.bat RPCServer.java
    > run.bat RPCServer

    Part of the application made up of:
       * RPCServer.java
       * RPCClient.java
*/

import org.jspace.*;

public class RPCServer
{
  private final static String GATE_URI = 
                  "tcp://127.0.0.1:9001/?keep";

  private final static String REMOTE_URI = 
                  "tcp://127.0.0.1:9001/rpcSpace?keep";
     // make sure the space name matches that in SpaceRepository.add();
     // this address will be used by clients of this server


  public static void main(String[] argv)
  {
    try {
      SpaceRepository repository = new SpaceRepository();
      repository.addGate(GATE_URI);
      Space space = new SequentialSpace();
      repository.add("rpcSpace", space);

      System.out.println("Contact RPCServer at: " + REMOTE_URI);

      Object[] args;
      // Keep serving requests; the server never terminates
      while (true) {
        // wait for a 'func' tuple from a caller
        Object[] request = space.get( new FormalField(String.class),
                                    new ActualField("func"),
                                    new FormalField(String.class));
        String caller = (String)request[0];
        String funcNm = (String)request[2];
        System.out.println("Serving request from " + caller + 
                                  " to run " + funcNm);
        switch (funcNm) {
          // wait for the function's 'args' tuple from caller
        case "add3":
          args = space.get(new ActualField(caller),
                              new ActualField("args"),
                              new FormalField(Integer.class),
                              new FormalField(Integer.class),
                              new FormalField(Integer.class));
          space.put(caller, "result", add3((Integer) args[2], 
                                        (Integer) args[3],
                                        (Integer) args[4]));
          break;

        case "concat":
          args = space.get(new ActualField(caller),
                              new ActualField("args"),
                              new FormalField(String.class),
                              new FormalField(String.class));
          space.put(caller, "result",
                  concat((String)args[2], (String)args[3]));
          break;

        default:  // ignore RPC for unknown functions
          System.out.println("-- but is unknown");
          break;
        } /* switch */
      }
    }
    catch (InterruptedException e) 
    {  System.out.println(e);  }
  } /* main */


  // the functions supported by this server;
  // Note that the result can be different types

  private static Integer add3(Integer x, Integer y, Integer z)
  {  return x + y + z;   }


  private static String concat(String x, String y)
  {  return x + y;   }


}  // end of RPCServer class
