home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer) / NeXT_Developer-3.3.iso / NextDeveloper / Examples / DistributedObjects / RemoteVote / VoteTally.m < prev   
Encoding:
Text File  |  1995-02-10  |  7.0 KB  |  262 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.     [clientList makeObjectsPerform:@selector(resetLocal:) with:self];
  193.     [self updateStats];
  194.     return self;
  195. }
  196.  
  197. /* reset is the same as moving all sliders.  So, we should notify hub 
  198.  * if the hub sent us this message, then it already knows 
  199.  */
  200. - resetLocal:sender
  201. {
  202.     int i,numRows,numCols;
  203.     [scrollers getNumRows:&numRows numCols:&numCols];
  204.     for ( i = 0 ; i < numCols; i++){
  205.     [[scrollers findCellWithTag:i] setIntValue:50]; 
  206.     }
  207.     if (sender != remoteHub)
  208.         [remoteHub updateStats];
  209.     return self;
  210. }
  211.  
  212. /* a slider has moved... have the hub query everyone for new stats */
  213. - takeVoteFrom:sender
  214. {
  215.    [remoteHub updateStats];
  216.    return self;
  217. }
  218.  
  219. /* ============================================================
  220.  *
  221.  * ============================================================ */
  222.  
  223. - getNumAttend:(int *)anInt
  224. {
  225.     *anInt = numAttendees;
  226.     return self;
  227. }
  228.  
  229. - getValue:(int *)aVal at:(int)index
  230. {
  231.     *aVal = [[scrollers findCellWithTag:index] intValue];
  232.     return self;
  233. }
  234.  
  235. - getMean:(float *)aFloat at:(int)index
  236. {
  237.     *aFloat = [[means findCellWithTag:index] floatValue];
  238.     return self;
  239. }
  240.  
  241. /* ============================================================
  242.  *
  243.  *    part of the registerForInvalidationNotification stuff
  244.  *
  245.  *
  246.  * ============================================================ */
  247.  
  248. - senderIsInvalid:sender
  249. {
  250.     if (self != remoteHub){
  251.         /* server is dead, so lets kill ourselves */
  252.     remoteHub = nil;
  253.     [NXApp terminate:self];
  254.     } else {
  255.         /* the server ran into a dead client */
  256.     [self removeClient:sender];
  257.     }
  258.     return self;
  259. }
  260.  
  261. @end
  262.