(Antiquity graphic)
Introduction
News
Search
Documentation License
Download
Contributors
Contact Us

Antiquity
Secure Log For Wide-Area Distributed Storage

Tutorials - Chat
  • Chat Tutorial - Programmer's Guide to Writing A Chat Application In the Bamboo System
    • Synopsis:
      • Given the structure of the Bamboo system and its extensive use of stages to separate functionality, as well as Remote Procedure Calls (RPC's) to communicate between stages we are going to build a chatting application to allow clients to communicate with one another through the use of text messages.
        • Note:
          • For testing purposes, the server and clients will be executed on the same machine
      • There will be a server who hosts the chat and clients who connect to the server based on a group id and a node id
        • The group id is used for allowing multiple chat rooms to exist
        • The node id is used to characterize the client's connection (IP Address and port) and user name
      • This server will be the central host for all messages. Meaning that in any instance when a client sends a message to the group they are in, it will be sent to the server, and the server will then forward it to everyone in the group
      • When the client begins to run the on the Bamboo system they will be prompted to enter the server's port as well as their own
      • After, they will enter in their name and group id
      • Upon joining the group (chat room) they will be greeted by the server who informs all the clients in the group that they have joined as well as place the newly joined client in a list of clients for that particular group
      • The user will then be allowed to send and receive text messages as well as status updates (when a client joins or leaves the group they are currently in)
        • Note:
          • Clients will only be allowed to see messages and status updates that occur after they have joined a group
      • To exit the system, the client simply types "quit" as their text message and this informs the server that the client has decided to leave and informs all of the other clients in the group, as well as removes the client from the list of joined members
    • 7 Required Files:
      • chat.x
      • chat_server.cfg
      • chat_cliient.cfg
      • ChatServer.java
      • ChatClient.java
      • chat.sh
      • Makefile
    • Description of Required Files:
      • chat.x
        • XDR File that outlines the events that will be used
          • The events are:
            • join - join the chat group
              • Arguments:
                • group id
                • node id
              • Results:
                • Join success
                • Join failure
            • send - send a message to the group
              • Arguments:
                • group id
                • node id
                • message
              • Results:
                • Send success
                • Send failure
            • leave - leave the chat group
              • Arguments:
                • group id
                • node id
              • Results:
                • Leave success
                • Leave failure
      • chat_server.cfg
        • Configuration file that pre-defines the settings used in the ChatServer stage
      • chat_cliient.cfg
        • Configuration file that pre-defines the settings used in the ChatClient stage
      • ChatServer.java
        • Java class that offers a client the ability to join, send a message and leave a chat group.
        • Stages Used:
          • ChatServer
          • RpcServer
          • RpcClient
          • RpcScheduler
          • See "Chat Process and Important Note" below for explanation
      • ChatClient.java
        • Java class that requests the ability to join, send a message and leave a chat group
        • Stages Used:
          • ChatClient
          • RpcClient
          • RpcScheduler
          • RpcServer
          • See "Chat Process and Important Note" below for explanation
      • chat.sh
        • Shell script that runs the chat_client.cfg. When the shell is run it requests the port of the server and the client to avoid having to edit the chat_client.cfg every time a new client wishes to run the chat application
      • Makefile
        • File that compiles the files: chat_server.cfg, chat_client.cfg, ChatServer.java, ChatClient.java
    • Chat Process:
      • It is important to note that since this application implements a chat application with the extensive use of RPC's, we will NOT be using any pre-existing communication protocols (i.e. TCP/IP, UDP etc) in the java library
      • Since we are not implementing any communication protocols the chat will function as follows:
        • Joining a chat group:
          • Client sends a "join" request to the Server
          • Server will receive the "join" request
          • Server adds the client to a map containing all the clients in the form of (group_id, node_id)
          • Server replies to the client that it has connected to the group successfully
          • Client will receive the "join" request reply and be allowed to enter and send text messages
          • Server will send a "send message" request to all existing members in the group, including the newly joined client, stored in the map of clients, that the client has joined the group
          • All clients that were sent the message, will receive the "send message" request from the server
          • All clients that were sent the message reply to the server that they have received the request
        • Sending a message to the chat group:
          • Client sends a "send message" request to the Server
          • Server will receive the "send message" request
          • Server replies to the client that it has received its "send message" request which holds the client's message to the group
          • Client will receive the reply that their "send message" request has been received by the server
          • Server will send a "send message" request to all existing members in the group, including the sending client, stored in the map of clients, that the client sent a message
          • All clients that were sent the message, will receive the "send message" request from the server
          • All clients that were sent the message reply to the server that they have received the "send message" request
        • Leaving a chat group:
          • Client sends a "leave" request to the Server
          • Server will receive the "leave" request
          • Server removes the client from the map containing all the clients in the form of (group_id, node_id)
          • Server replies to the client that it has left the group successfully
          • Client will receive the "leave" request reply and exit's the application
          • Server will send a "send message" request to all existing members in the group, not including the leaving client, stored in the map of clients, that the client has left the group
          • All clients that were sent the message, will receive the "send message" request from the server
          • All clients that were sent the message reply to the server that they have received the "send message" request
      • Important Note:
        • Since both Server and Client need to send and receive RPC's from one another they both need to implement the the RpcServerStage, RpcClientStage and RpcScheduler
    • Chat Code
      • Chat XDR File (chat.x)
        • We need to establish the event results, the types group id and node id to identify a client and the group they choose to be a part of, and the 3 RPC events, join, send message, leave by defining their arguments and results
          • Note:
            • Remember we have to organize each data set as structures (similar to that in C and C++) except for the event results which will be expressed through the use of an enumerator
        • enum ChatStatus
          • We need to establish a success and failure for each event:
            • CHAT_STATUS_JOIN_OK
            • CHAT_STATUS_JOIN_ERROR
            • CHAT_STATUS_MSG_SENT_OK
            • CHAT_STATUS_MSG_SENT_ERROR
            • CHAT_STATUS_LEAVE_OK
            • CHAT_STATUS_LEAVE_ERROR
        • Node Id:
          • struct chat_node_id
            • We have to identify each node (client) by their user name, IP address and its port
            • String user_name
            • String addr
            • int port
        • Group Id:
          • struct chat_group_id
            • int group
        • Join Arguments:
          • struct chat_join_args
            • All that is required to join a chat group is the group id and the client's node id
            • chat_group_id group_id
            • chat_node_id node_id;
        • Join Results:
          • struct chat_join_result
            • ChatStatus status
        • Send Message Arguments:
          • To send a message we require the group id the message is being sent to, the node id (client sending it) and the message itself
          • struct chat_sendmsg_args
            • chat_group_id group_id;
            • chat_node_id node_id;
            • String msg;
        • Send Message Results:
          • struct chat_sendmsg_result
            • ChatStatus status
        • Leave Arguments:
          • struct chat_leave_args
            • All that is required to leave a chat group is the group id and the client's node id
            • chat_group_id group_id
            • chat_node_id node_id;
        • Leave Results:
          • struct chat_leave_result
            • ChatStatus status
        • RPC Triple Identifier
          • Recall:
            • Each event has an associated RPC, of which is identified in XDR standard by a (ProgramNumber, VersionNumber, ProcedureNumber). The numbers set here are arbitrary:
              • program CHAT_API
              • {
              • version CHAT_API_VERSION
              • {
              • void
              • chat_null(void) = 1001;

              • chat_join_result
              • chat_join(chat_join_args) = 1002;

              • chat_sendmsg_result
              • chat_sendmsg(chat_sendmsg_args) = 1003;

              • chat_leave_result
              • chat_leave(chat_leave_args) = 1004;

              • } = 1;
              • } = 0x00002112;
      • Chat Server
        • Configuration File (chat_server.cfg)
          • We need to establish all 4 stages that ChatServer will be using
            • ChatServer:
              • Set the class variable to be the location of the ChatServer class (in this case, the files are stored in a directory known as /chat/ located in /antiquity/src/moxie/
                • class moxie.chat.ChatServer
              • Create the address and port for the RpcServer Stage that this Server is running it on
                • RpcServerName localhost
                • RpcServerPort 10000
            • RpcServer:
              • Set the port to be in sync with the port used in the ChatServer Stage for the RPCServer that the Server is running
                • port 10000
            • RpcClient - remain standard
            • RpcScheduler - remain standard
        • Java Class (ChatServer.java)
          • init(ConfigDataIF config)
            • Listen for the event StagesInitialized to notify us that all stages used have been initialized
              • event_types = new Object[]{ seda.sandStorm.api.StagesInitializedSignal.class
                };
            • Store the configuration settings from chat_server.cfg and create the application's node id
              • rpc_server_name = config.getString("RpcServerName");
              • rpc_server_port = config.getInt("RpcServerPort");
              • rpc_node_id = new NodeId(rpc_server_port, my_node_id.getAddress());
            • Create a hashmap that holds all the clients that connect to the server using the group id (Integer) as the key and the value be another map holding a type NodeId (port, address) and user_name (String)
              • all_clients = new HashMap<>();
          • handleEvent(QueueElementIF event)
            • Sets the local rpc_server_stage variable to the instance of the node's id in the RpcServerStage
              • rpc_server_stage = RpcServerStage.getInstance(rpc_node_id);
            • Map the RPC identifiers to the RPC handlers
              • registerRpcProcedures();
            • Register the RPC scheduler used to send messages to this node's id, retrieve the RPC calls that the ChatClient is offering, and register the ChatClient's RPC call's along with the assigned callback with the RPC scheduler
              • rpc_scheduler = RpcScheduler.getInstance(my_node_id);
              • assert(rpc_scheduler != null);
              • Map client_proc_map = ChatClient.getChatProcedureMap();
              • rpc_scheduler.registerRpcProcedures(client_proc_map, reg_rpc_cb);
                • reg_rpc_cb()
                  • Log that the events that the ChatClient is offering to the ChatServer are registered
                    • logger.info("Done registering RPC handlers.");
          • registerRpcProcedures()
            • Create a RPCRegisterRequest variable that contains information regarding the application as well as the procedure numbers of the events the stage is responsible for
              • boolean client = false;
              • rpc_app_id = bamboo.router.Router.app_id(ChatServer.class);
              • Object user_data = null;
              • SinkIF sink = (SinkIF) null;
              • RpcRegisterReq rpc_register_req = new RpcRegisterReq(getChatProcedureMap(), client, rpc_app_id, user_data, sink);
                • Note:
                  • See getChatProcedureMap() below for details on the registration of the events offered
            • Register a callback method for rpc_register_req and provide the same method for each of the procedures' handler stored in the RPCRegisterRequest
              • rpc_register_req.cb = register_rpc_proc_done;
              • rpc_register_req.handlers = new HashMap>();
              • for (ProcKey key : rpc_register_req.procedures.keySet()) rpc_register_req.handlers.put(key, handle_rpc_call);
            • Register the RPCRegisterRequest with the RPCServerStage
              • rpc_server_stage.handleEvent(rpc_register_req);
          • getChatProcedureMap()
            • Retrieve the chat_procedure_map that builds the map of the events' procedure number's that the Server is offering
              • int CHAT_API = chat.CHAT_API;
              • int CHAT_API_VERSION = chat.CHAT_API_VERSION;

              • chat_proc_map = new HashMap();

              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_null_1),
                new ProcValue(XdrVoid.class, XdrVoid.class));
              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_join_1),
                new ProcValue(chat_join_args.class, chat_join_result.class));
              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_sendmsg_1),
                new ProcValue(chat_sendmsg_args.class, chat_sendmsg_result.class));
              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_leave_1),
                new ProcValue(chat_leave_args.class, chat_leave_result.class));

              • return chat_proc_map;
          • register_rpc_proc_done()
            • Run through the entries of events registered with RPCRegisterRequest and look for report their success or failure
              • for (Map.Entry entry : rpc_register_resp.responses.entrySet())
              • if (! RpcRegisterResp.SUCCESS.equals(entry.getValue()))
                BUG("Failed to register RPC procedure: " +
                " proc_key=" + entry.getKey());
          • handle_rpc_call()
            • Map the rpc_call that arrived at the node to its assigned method based on the event's procedure number
              • switch (proc_num)
              • {
              • case chat.chat_null_1: handleNull(rpc_call); break;
              • case chat.chat_join_1: handleJoin(rpc_call); break;
              • case chat.chat_sendmsg_1: handleSendMsg(rpc_call); break;
              • case chat.chat_leave_1: handleLeave(rpc_call); break;
              • default:
              • logger.fatal("Received unexpected request: " +
                "proc_num=" + proc_num);
              • break;
              • }
          • handleNull(RpcCall rpc_call)
            • Create void arguments from XDR and use them to reply to the rpc_call through the rpc_server_stage
              • XdrVoid args = XdrVoid.XDR_VOID;
              • RpcReply rpc_reply = new RpcReply(args, rpc_call);
              • rpc_server_stage.handleEvent(rpc_reply);
          • handleJoin(RpcCall rpc_call)
            • Create ChatJoin Arguments from the rpc_call and a RPCReply object to use to respond to the client
              • chat_join_args chat_join_args = (chat_join_args) rpc_call.args;
              • chat_join_result result = new chat_join_result();
              • RpcReply rpc_reply;
            • Create a map of all the clients NodeId and user_name that are in the same group as the client who made the rpc_call
              • Map group = all_clients.get(chat_join_args.group_id.group);
            • Create a key for the client who made the rpc_call
              • NodeId key = new NodeId(chat_join_args.node_id.addr+":"+ chat_join_args.node_id.port);
            • Create the entry for the client in the list of all_clients
              • group = new HashMap();
              • all_clients.put(chat_join_args.group_id.group, group);
            • Actually fill the client's entry in the list of all_clients with their key (NodeId, user_name) if its key isn't null and the group does not already contain the client, and set the reply of the request
              • group.put(key, chat_join_args.node_id.user_name);
              • result.status = ChatStatus.CHAT_STATUS_JOIN_OK;
            • Send a reply back to the client who made the rpc_call to inform them the status of their request
              • rpc_reply = new RpcReply(result, rpc_call);
              • rpc_server_stage.handleEvent(rpc_reply);
            • Create a sendmsg argument to use in notifying all the clients of the group, that the client has joined
              • chat_sendmsg_args chat_sendmsg_args = new
              • chat_sendmsg_args();
              • chat_sendmsg_args.group_id = new chat_group_id();
              • chat_sendmsg_args.node_id = new chat_node_id();

              • chat_sendmsg_args.group_id.group =
              • chat_join_args.group_id.group;
              • chat_sendmsg_args.node_id.user_name = "Server";
              • chat_sendmsg_args.node_id.addr = rpc_server_name;
              • chat_sendmsg_args.node_id.port = rpc_server_port;
              • chat_sendmsg_args.msg = chat_join_args.node_id.user_name + " joined the group.";
            • Send the message to all the clients in the group
              • sendMsg(chat_sendmsg_args);
          • handleSendMsg(RpcCall rpc_call)
            • Create ChatSendMsg Arguments from the rpc_call and a RPCReply object to use to respond to the client
              • chat_sendmsg_args chat_sendmsg_args = (chat_sendmsg_args) rpc_call.args;
              • chat_sendmsg_result result = new chat_sendmsg_result();
              • RpcReply rpc_reply;
            • Set the status of the client's request to being received by the Server
              • result.status = ChatStatus.CHAT_STATUS_MSG_SENT_OK;
            • Send a reply back to the client informing them of the status of their request
              • rpc_reply = new RpcReply(result, rpc_call);
              • rpc_server_stage.handleEvent(rpc_reply);
            • Forward the message sent by the client to the server, to all the clients pertaining to the client's group
              • sendMsg(chat_sendmsg_args);
          • sendMsg(chat_sendmsg_args chat_sendmsg_args)
            • Create a mapping of all the clients that share the same group id as the one in the chat_sendmsg_args
              • Map group = all_clients.get(chat_sendmsg_args.group_id.group);
            • Proceed through the map just created of all the clients and set up the callback for the sending of the message and then actually send them the message in the chat_sendmsg_args
              • for (Map.Entry entry : group.entrySet()){
              • NodeId client_addr = entry.getKey();
              • String user_name = entry.getValue();

              • ProcKey proc_key =
              • new ProcKey(chat.CHAT_API, chat.CHAT_API_VERSION,
                chat.chat_sendmsg_1);
              • PriorityRpcCall rpc_call =
                new PriorityRpcCall(client_addr, proc_key,chat_sendmsg_args, PriorityRpcCall.PRIORITY_HIGHEST,
                rpc_app_id);
              • rpc_call.cb = sendmsg_cb;
              • rpc_scheduler.send(rpc_call);
              • }
            • send_msg_cb()
              • When receiving the reply from all the clients who were sent the message, we check to see if any of the clients that were sent the message happened to appear on the map of all_clients even after leaving (in other words, they weren't removed from the map), if so, we remove them
                • if(!((rpc_reply.reply_stat == RpcReply.ReplyStat.MSG_ACCEPTED) &&
                  (rpc_reply.msg_accepted == RpcReply.AcceptStat.SUCCESS) &&
                  (rpc_reply.auth_accepted == RpcReply.AuthStat.AUTH_OK)))
                • {
                • boolean removed = _leave(args.group_id.group, rpc_call.peer);

                • logger.warn("Error sending msg")

                • return;
                • }
              • Process the reply from the client(s) who were sent the message
                • chat_sendmsg_result reply_args =
                • (chat_sendmsg_result) rpc_reply.reply;
                • int status = reply_args.status;

                • logger.info("Received sendMsg() reply from Clients: msg=" + msg + " status=" + status);
          • handleLeave(RpcCall rpc_call)
            • Remove the client leaving the group from the map, and if successful, reply to the leaving client that the leave was successful, and message the departure of the client to all the other clients in the group
              • boolean removed = _leave(chat_leave_args.group_id.group,
                chat_leave_args.node_id);
              • rpc_reply = new RpcReply(result, rpc_call);
              • rpc_server_stage.handleEvent(rpc_reply);

              • chat_sendmsg_args chat_sendmsg_args = new chat_sendmsg_args();
              • chat_sendmsg_args.group_id = new chat_group_id();
              • chat_sendmsg_args.node_id = new chat_node_id();

              • chat_sendmsg_args.group_id.group =
              • chat_leave_args.group_id.group;
              • chat_sendmsg_args.node_id.user_name = "Server";
              • chat_sendmsg_args.node_id.addr = rpc_server_name;
              • chat_sendmsg_args.node_id.port = rpc_server_port;
              • chat_sendmsg_args.msg = chat_leave_args.node_id.user_name +
                " left the group.";
              • sendMsg(chat_sendmsg_args);
      • Chat Client
        • Configuration File (chat_client.cfg)
          • We need to establish all 4 stages that ChatClient will be using
            • ChatClient:
              • Set the class variable to be the location of the ChatClient class (in this case, the files are stored in a directory known as /chat/ located in /antiquity/src/moxie/
                • class moxie.chat.ChatClient
              • Create the address and port for the RpcServer Stage that the actual Server is running
                • ServerName localhost
                • ServerPort ${ServerPort}
                  • Note:
                    • The ${...} variable for the port is substituted by a shell variable that will be filled in once the shell script we create (that will be the one actually running chat_client.cfg) is ran
              • Create the address and port for the RpcServer Stage that this Client is running it on
                • RpcServerName localhost
                • RpcServerPort ${LocalPort}
                  • Note:
                    • The ${...} variable for the port is substituted by a shell variable that will be filled in once the shell script we create (that will be the one actually running chat_client.cfg) is ran
            • RpcClient - remain standard
            • RpcScheduler - remain standard
            • RpcServer:
              • Set the port to be in sync with the port used in the ChatClient Stage for the RPCServer that the Client is running
                • port ${LocalPort}
                  • Note:
                    • The ${...} variable for the port is substituted by a shell variable that will be filled in once the shell script we create (that will be the one actually running chat_client.cfg) is ran
        • Java Class (ChatClient.java)
          • init(ConfigDataIF config)
            • Listen for the event StagesInitialized to notify us that all stages used have been initialized
              • event_types = new Object[]{ seda.sandStorm.api.StagesInitializedSignal.class
                };
            • Store the configuration settings from chat_server.cfg and create the application's node id
              • rpc_server_name = config.getString("RpcServerName");
              • rpc_server_port = config.getInt("RpcServerPort");
              • rpc_node_id = new NodeId(rpc_server_port, my_node_id.getAddress());
            • Prompt user to enter their user name and group id
              • System.err.println("Please enter name:\n");
              • System.err.flush();
              • Scanner in = new Scanner(System.in);
              • user_name = in.nextLine();

              • System.err.println("Please enter chat room ID:\n");
              • System.err.flush();
              • group_id = new Integer(in.nextLine());
          • handleEvent(QueueElementIF event)
            • Sets the node's application id (rpc_app_id) to function wih the Bamboo router
              • rpc_app_id = bamboo.router.Router.app_id(ChatClient.class);
            • Register the RPC scheduler used to send messages to this node's id, retrieve the RPC calls that the ChatClient is offering, and register the ChatClient's RPC call's along with the assigned callback with the RPC scheduler
              • rpc_scheduler = RpcScheduler.getInstance(my_node_id);
              • assert(rpc_scheduler != null);
              • Map client_proc_map = ChatClient.getChatProcedureMap();
              • rpc_scheduler.registerRpcProcedures(client_proc_map, reg_rpc_cb);
                • reg_rpc_cb()
                  • Log that the events that the ChatServer is offering to the ChatClient are registered, and register the acore in Bamboo to run a seperate thread to join the Server
                    • logger.info("Done registering RPC handlers.");
                    • _acore.register_timer(0, joinServer);
            • Create a server stage on the client to offer to the actual server the ability to send messages
              • rpc_server_stage = RpcServerStage.getInstance(rpc_node_id);
            • Map the RPC identifiers to the RPC handlers
              • registerRpcProcedures();
          • registerRpcProcedures()
            • Same as in ChatServer.java
          • getChatProcedureMap()
            • Retrieve the chat_procedure_map that builds the map of the events' procedure number's that the Server is offering
              • int CHAT_API = chat.CHAT_API;
              • int CHAT_API_VERSION = chat.CHAT_API_VERSION;

              • chat_proc_map = new HashMap();

              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_sendmsg_1),
                new ProcValue(chat_sendmsg_args.class, chat_sendmsg_result.class));

              • return chat_proc_map;
          • register_rpc_proc_done()
            • Same as in ChatServer.java
          • handle_rpc_call
            • Map the rpc_call that arrived at the node to its assigned method based on the event's procedure number
              • switch (proc_num)
              • {
              • case chat.chat_sendmsg_1: handleSendMsg(rpc_call); break;
              • default:
              • logger.fatal("Received unexpected request: " + "proc_num" + proc_num);
              • break;
              • }
          • handleSendMsg(RpcCall rpc_call)
            • Same as ChatServer.java excluding the sendMsg() call
            • Print out the message
              • System.err.println(args.node_id.user_name + " says: " + args.msg);
          • joinServer()
            • Create a chat_join-args type and fill it with this node's information
              • chat_join_args chat_join_args = new chat_join_args();

              • chat_join_args.group_id = new chat_group_id();
              • chat_join_args.node_id = new chat_node_id();

              • chat_join_args.group_id.group = group_id;
              • chat_join_args.node_id.user_name = user_name;
              • chat_join_args.node_id.addr = rpc_server_name;
              • chat_join_args.node_id.port = rpc_server_port;
            • Build an rpc_call to send the chat_join_args to the Server to request a join to the group
              • ProcKey key =
                new ProcKey(chat.CHAT_API, chat.CHAT_API_VERSION,
                chat.chat_join_1);
              • PriorityRpcCall rpc_call =
              • new PriorityRpcCall(server_addr, key, chat_join_args, PriorityRpcCall.PRIORITY_HIGHEST,
                rpc_app_id);
            • Register a callback for the join request the client made to the server and send the join request to the Server
              • rpc_call.cb = join_cb;
              • rpc_scheduler.send(rpc_call);
                • join_cb
                  • Receive reply from the Server and print out the status of the join request made by the client
                    • chat_join_result reply_args =
                      (chat_join_result) rpc_reply.reply;
                    • int status = reply_args.status;
                  • Create and start a new thread to continuously prompt the user for a message they wish to send to the chat
                    • Thread t = new Thread(new ChatPrompt());
                    • t.setName("ChatPrompt-" + rpc_server_port);
                    • t.start();
          • leaveServer()
            • Create a chat_leave_args type to request a leave from the server and fill it with this node's information
              • chat_leave_args chat_leave_args = new chat_leave_args();

              • chat_leave_args.group_id = new chat_group_id();
              • chat_leave_args.node_id = new chat_node_id();

              • chat_leave_args.group_id.group = group_id;
              • chat_leave_args.node_id.user_name = user_name;
              • chat_leave_args.node_id.addr = rpc_server_name;
              • chat_leave_args.node_id.port = rpc_server_port;
            • Build an rpc_call to send the chat_leave_args to the Server to request a leave from the group
              • ProcKey key = new ProcKey(chat.CHAT_API, chat.CHAT_API_VERSION,
                chat.chat_leave_1);
              • PriorityRpcCall rpc_call =
                new PriorityRpcCall(server_addr, key, chat_leave_args,
                PriorityRpcCall.PRIORITY_HIGHEST,
                rpc_app_id);
            • Register a callback for the leave request the client made to the server and send the leave request to the Server
              • rpc_call.cb = leave_cb;
              • rpc_scheduler.send(rpc_call);
                • leave_cb()
                  • Receive reply from the Server and print out the status of the leave request made by the client
                    • chat_leave_result reply_args =
                      (chat_leave_result) rpc_reply.reply;
                    • int status = reply_args.status;
                  • Exit the chat application
                    • System.err.println("Exiting");
                    • System.err.flush();
                    • System.exit(0);
          • buildMsg(String msg)
            • Create a chat_sendmsg_args type to request a send message from the server and fill it with this node's information
              • chat_sendmsg_args chat_sendmsg_args = new chat_sendmsg_args();
              • chat_sendmsg_args.group_id = new chat_group_id();
              • chat_sendmsg_args.node_id = new chat_node_id();

              • chat_sendmsg_args.group_id.group = group_id;
              • chat_sendmsg_args.node_id.user_name = user_name;
              • chat_sendmsg_args.node_id.addr = rpc_server_name;
              • chat_sendmsg_args.node_id.port = rpc_server_port;
              • chat_sendmsg_args.msg = msg;
            • Build an rpc_call to send the chat_sendmsg_args to the Server to request a sendmsg to the group
              • ProcKey key =
                new ProcKey(chat.CHAT_API, chat.CHAT_API_VERSION,
                chat.chat_sendmsg_1);
                PriorityRpcCall rpc_call =
                new PriorityRpcCall(server_addr, key, chat_sendmsg_args,

              • PriorityRpcCall.PRIORITY_HIGHEST, rpc_app_id);
            • Register a callback for the sendmsg request the client made to the server and send the sendmsg request to the Server
              • rpc_call.cb = sendmsg_cb;
              • rpc_scheduler.send(rpc_call);
                • sendmsg_cb
                  • Receive reply from the Server and print out the status of the sendmsg request made by the client
                    • chat_sendmsg_result reply_args =
                      (chat_sendmsg_result)
                    • rpc_reply.reply;
                    • int status = reply_args.status;
          • chat_proc_map()
            • Place the event's procedure numbers in the map of all events offered by the Client
              • int CHAT_API = chat.CHAT_API;
              • int CHAT_API_VERSION = chat.CHAT_API_VERSION;

              • chat_proc_map = new HashMap();
              • chat_proc_map.put(
                new ProcKey(CHAT_API, CHAT_API_VERSION, chat.chat_sendmsg_1),
                new ProcValue(chat_sendmsg_args.class, chat_sendmsg_result.class));

              • return chat_proc_map;
          • ChatPrompt()
            • Consistantly prompt the client to enter a message to send to the group they are in. Also, by typing "quit" they signal the server that they wish to leave
              • Scanner in = new Scanner(System.in);
              • while(true)
              • {
              • System.err.println("Enter a message to send (or type quit):\n");
              • String msg = in.nextLine();
              • if(msg.equals("quit"))
              • {
              • _acore.register_timer(0, leaveServer);
              • break;
              • }
              • buildMsg(msg);
              • }
        • Shell Script (chat.sh)
          • Assure all the necessary directories are available for usage
            • if [ -z "${ANTIQUITY_DIR}" ] then
            • if [ -d ${HOME}/antiquity ] then
            • ANTIQUITY_DIR=${HOME}/antiquity
            • elif [ -d ${HOME}/Oceanstore/antiquity ]
            • then

            • ANTIQUITY_DIR=${HOME}/Oceanstore/antiquity
            • else
            • usage2
            • exit 1
            • fi
            • fi

            • ANTIQUITY_SRC_DIR=${ANTIQUITY_DIR}/src/antiquity
            • if [ -z "${TMP}" ] then
            • if [ -d /tmp ] then
            • TMP="/tmp"
            • else
            • usage2
            • exit 1
            • fi
            • fi
            • if [[ "$#" -ne "2" ]] then
            • usage
            • exit 1
            • fi
          • Create the actual configuration file (chat_client.cfg) for each instance that it is run
            • SERVER_PORT=$1
            • LOCAL_PORT=$2
            • NAME=chat-${LOCAL_PORT}

            • FILE=${ANTIQUITY_DIR}/src/moxie/chat/chat_client.cfg
            • CFG=${TMP}/${NAME}.cfg
            • LOG=${TMP}/${NAME}.log

            • # replace fields in configuration file
            • sed -e "s/\\\${LocalPort}/${LOCAL_PORT}/" ${FILE} |
            • sed -e "s/\\\${ServerPort}/${SERVER_PORT}/" > $CFG
      • Makefile
        • This makefile is the same format as every makefile used throughout the ~/antiquity/src/moxie/ directory.
        • The only differences with this make file is directory related:
          • Assure the following variables point to the right files in ~/antiquity/src/moxie/chat/ directory:
            • RPC_SOURCE_FILES = \
            • $(shell ../../../bin/extract_xdr_types.pl chat.x | sed s/$$/.java/)
            • RPC_OBJECT_FILES =$(RPC_SOURCE_FILES:.java=.class)
            • $(RPC_SOURCE_FILES): chat.x
            • $(MOXIE_HOME)/bin/run-java -jar $(MOXIE_HOME)/lib/jrpcgen.jar -nobackup -noclient -noserver -p moxie.chat $<

            • cvsignore:
            • echo "*.class" > .cvsignore
            • ../../../bin/extract_xdr_types.pl chat.x | sed s/$$/.java/ >> .cvsignore
            • Note:
              • See any Makefile in the directory ~/antiquity/src/moxie/


Last modified 2007/08/17.