home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / DistributedObjects / RemoteVote / VoteTally.m < prev   
Encoding:
Text File  |  1993-08-20  |  7.0 KB  |  263 lines

  1.  
  2. /* 
  3.  *    VoteTally.m    Written by Joe Freeman 5/27/92
  4.  *
  5.  * Note: 
  6.  *    You can talk back to a remote object, if it gives you
  7.  *     its id.  But, you cannot, while responding to a message that came 
  8.  *     remote, send a message to a remote server in the same process.  That  
  9.  *     be blocked out by the conversation that you are responding to.
  10.  *
  11.  *    You can talk to the NXConnection object in the client, that
  12.  *    was created when connecting to the server, if the client has
  13.  *    done a runFromAppkit using that connection object
  14.  *
  15.  * Also,
  16.  *    clientList = nil if we are not the server
  17.  *
  18.  */
  19. #import "VoteTally.h"
  20.  
  21. @implementation VoteTally
  22.  
  23. #define numAttendees    ([clientList count] )
  24. - appDidInit:sender
  25. {
  26.  
  27.     /* You should really give it the name of the machine you want it to
  28.      * connect to. The "*" will cause the server to look at every machine
  29.      * on the subnet.  That could take a LONG time.
  30.      */
  31.     remoteHub = [NXConnection connectToName:"VoteTally" onHost:"*"];
  32.     if (remoteHub){
  33.         [clearAllMenu setEnabled:NO];
  34.     
  35.     /* if someone is already the hub, then we will be the client
  36.       * we find the NXConnection object that is handling the Proxy
  37.      * that represents the vote server.  We then register this object
  38.      * to handle errors for that server 
  39.      *
  40.      * the client understands more than this protocol 
  41.      * but these are used most so lets tell it about the them.
  42.      */
  43.     [[scrollers window] setTitle: "Voting Client"];
  44.         ourServer = [remoteHub connectionForProxy];
  45.     [remoteHub setProtocolForProxy:@protocol(VoteTallyServerMethods)];
  46.  
  47.     } else {
  48.     /* The fact that no one is registered, means that we are going to
  49.      * be the server.  So, we register our connection 
  50.      * 
  51.      * The server understands the client protocol also 
  52.      * but these are the most common messages
  53.      */
  54.     clientList = [[List alloc] init];
  55.     [[scrollers window] setTitle: "Voting Server"];
  56.     ourServer = [NXConnection registerRoot: self withName:"VoteTally"];
  57.     
  58.     /* add ourselves as a psuedo client */
  59.     remoteHub = self;
  60.     }
  61.  
  62.     /* 
  63.      *    we take ourServer, which represets the NXConnection objec that
  64.      *  will handle all our proxys (?) and make ourselves the handler for
  65.      *  errors for that object.  Then we run from appkit.
  66.      *
  67.      *    The case for the voting server makes sense.  We need to run from
  68.      *    appkit so that we can server all the clients.  
  69.      *
  70.      *    The case for the clients is not as clear.   We register the 
  71.      *    NXConnection that is behind our connection to the vote server
  72.      *    so that the server, which will have our ID will be able to talk
  73.      *    back without the client having initiated the connection.  This is
  74.      *    NOT OBVIOUS from the PR1 docs
  75.      */
  76.     [ourServer registerForInvalidationNotification:self];
  77.     [ourServer runFromAppKit];
  78.     [remoteHub addClient:self];
  79.  
  80.     return self;
  81. }
  82.  
  83. - appWillTerminate:sender
  84. {
  85.     [remoteHub removeClient:self];
  86.     return self;
  87. }
  88.  
  89. - free
  90. {
  91.     [super free];
  92.     [ourServer free];
  93.     return self;
  94. }
  95.  
  96. /* ============================================================
  97.  *    who is part of this conference anyway?
  98.  *
  99.  *    All three of these messages may cause traffic to ALL the
  100.  *     clients which means the NXConnection objects on those 
  101.  *    need to be free.  So, we declare these oneway to release
  102.  *
  103.  * ============================================================ */
  104.  
  105. - addClient:sender
  106. {
  107.     id connectionToClient;
  108.     
  109.     if (sender != self){
  110.         /* do some error trapping and optimizaitons */
  111.     
  112.         /* figure out who is behind this new client and get their errors */
  113.         connectionToClient = [sender connectionForProxy];
  114.         [connectionToClient registerForInvalidationNotification:self];
  115.             
  116.         /* make sure this new object is smart about the client messages */
  117.         [sender setProtocolForProxy:@protocol(VoteTallyClientMethods)];
  118.     }
  119.     
  120.     /* do some bookeeping */
  121.     [clientList addObjectIfAbsent:sender];
  122.     [self updateStats];
  123.     return self;
  124. }
  125.  
  126. - removeClient:anObject
  127. {
  128.     [clientList removeObject:anObject];
  129.     if ( anObject != self ){
  130.         /* the server should rebuild the stats */
  131.     [self updateStats];
  132.     }
  133.     return self;
  134. }
  135.  
  136. /* an updateStats:message means two different things, depending on server
  137.  * Server    rebuilds the stats and then tells all clients to get stats
  138.  * Client    gets all the stats from the server
  139.  */
  140. #define NUMSLIDERS 6
  141.  
  142. -  (void) updateStats
  143. {
  144.     int last = numAttendees;
  145.     int i,s;
  146.     float sliders[NUMSLIDERS];
  147.     float tmp;
  148.     int   iTmp;
  149.  
  150. ///    fprintf(stderr,"%d updateStats with remote hub = %d\n", self, remoteHub);
  151.  
  152.     [remoteHub getNumAttend:&i];
  153.     [numVoting setIntValue: i];
  154.     
  155.     if (remoteHub != self){
  156.     for ( s = 0 ; s < NUMSLIDERS; s++){
  157.         [remoteHub getMean:&tmp at:s];
  158.         [[means findCellWithTag:s] setFloatValue:tmp];
  159.     }
  160.     
  161.     } else {
  162.         /* build new stats */
  163.     for ( s = 0 ; s < NUMSLIDERS; s++){
  164.         sliders[s] = 0.0;
  165.         for ( i = 0 ; i < last; i++){
  166.             [[clientList objectAt:i] getValue:&iTmp at:s];
  167.             sliders[s]+= iTmp;
  168.         }
  169.         sliders[s] = sliders[s]/numAttendees;
  170.         [[means findCellWithTag:s] setFloatValue:sliders[s]];
  171.     }
  172.  
  173. ///    fprintf(stderr,"%d stats rebuilt \n", self);
  174.     /* tell all the clients to update their displays from us */
  175.     for ( i = 0 ; i < last ; i++){
  176.         if ([clientList objectAt:i] != self)
  177.             [[clientList objectAt:i] updateStats];
  178.      }
  179.     }
  180. }
  181.  
  182.  
  183. /* ============================================================
  184.  *
  185.  * ============================================================ */
  186.  
  187. /* 
  188.  * only the hub is allowed to restore everyone's score
  189.  */
  190. - resetAll:sender
  191. {
  192.     int last = numAttendees;
  193.     [clientList makeObjectsPerform:@selector(resetLocal:) with:self];
  194.     [self updateStats];
  195.     return self;
  196. }
  197.  
  198. /* reset is the same as moving all sliders.  So, we should notify hub 
  199.  * if the hub sent us this message, then it already knows 
  200.  */
  201. - resetLocal:sender
  202. {
  203.     int i,numRows,numCols;
  204.     [scrollers getNumRows:&numRows numCols:&numCols];
  205.     for ( i = 0 ; i < numCols; i++){
  206.     [[scrollers findCellWithTag:i] setIntValue:50]; 
  207.     }
  208.     if (sender != remoteHub)
  209.         [remoteHub updateStats];
  210.     return self;
  211. }
  212.  
  213. /* a slider has moved... have the hub query everyone for new stats */
  214. - takeVoteFrom:sender
  215. {
  216.    [remoteHub updateStats];
  217.    return self;
  218. }
  219.  
  220. /* ============================================================
  221.  *
  222.  * ============================================================ */
  223.  
  224. - getNumAttend:(int *)anInt
  225. {
  226.     *anInt = numAttendees;
  227.     return self;
  228. }
  229.  
  230. - getValue:(int *)aVal at:(int)index
  231. {
  232.     *aVal = [[scrollers findCellWithTag:index] intValue];
  233.     return self;
  234. }
  235.  
  236. - getMean:(float *)aFloat at:(int)index
  237. {
  238.     *aFloat = [[means findCellWithTag:index] floatValue];
  239.     return self;
  240. }
  241.  
  242. /* ============================================================
  243.  *
  244.  *    part of the registerForInvalidationNotification stuff
  245.  *
  246.  *
  247.  * ============================================================ */
  248.  
  249. - senderIsInvalid:sender
  250. {
  251.     if (self != remoteHub){
  252.         /* server is dead, so lets kill ourselves */
  253.     remoteHub = nil;
  254.     [NXApp terminate:self];
  255.     } else {
  256.         /* the server ran into a dead client */
  257.     [self removeClient:sender];
  258.     }
  259.     return self;
  260. }
  261.  
  262. @end
  263.