StropheCappuccino API 1.0.0
/tmp/tempDoc.doc/PubSub/TNPubSubController.j
Go to the documentation of this file.
00001  /*
00002   * TNPubSubController.j
00003   *
00004   * Copyright (C) 2010 Ben Langfeld <ben@langfeld.me>
00005   *
00006   * This library is free software; you can redistribute it and/or
00007   * modify it under the terms of the GNU Lesser General Public
00008   * License as published by the Free Software Foundation; either
00009   * version 3.0 of the License, or (at your option) any later version.
00010   *
00011   * This library is distributed in the hope that it will be useful,
00012   * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   * Lesser General Public License for more details.
00015   *
00016   * You should have received a copy of the GNU Lesser General Public
00017   * License along with this library; if not, write to the Free Software
00018   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019   */
00020 
00021 
00022 
00023 
00024 TNStrophePubSubBatchSubscribeCompleteNotification       = @"TNStrophePubSubBatchSubscribeCompleteNotification";
00025 TNStrophePubSubBatchUnsubscribeCompleteNotification     = @"TNStrophePubSubBatchUnsubscribeCompleteNotification";
00026 TNStrophePubSubNoOldSubscriptionsLeftNotification       = @"TNStrophePubSubNoOldSubscriptionsLeft";
00027 TNStrophePubSubSubscriptionsRetrievedNotification       = @"TNStrophePubSubSubscriptionsReceivedNotification";
00028 
00029 
00033 @implementation TNPubSubController : CPObject
00034 {
00035     CPArray         _nodes;
00036     CPArray         _servers;
00037     id              _delegate;
00038 
00039     CPDictionary    _subscriptionBatches;
00040     CPDictionary    _unsubscriptionBatches;
00041     id              _connection;
00042     int             _numberOfPromptedServers;
00043 }
00044 
00045 #pragma mark -
00046 #pragma mark Class methods
00047 
00053 + (TNPubSubNode)pubSubControllerWithConnection:(TNStropheConnection)aConnection pubSubServer:(CPString)aPubSubServer
00054 {
00055     return [[TNPubSubController alloc] initWithConnection:aConnection pubSubServer:aPubSubServer];
00056 }
00057 
00062 + (TNPubSubNode)pubSubControllerWithConnection:(TNStropheConnection)aConnection
00063 {
00064     return [[TNPubSubController alloc] initWithConnection:aConnection pubSubServer:nil];
00065 }
00066 
00067 
00068 #pragma mark -
00069 #pragma mark Initialization
00070 
00076 - (TNPubSubNode)initWithConnection:(TNStropheConnection)aConnection pubSubServer:(TNStropheJID)aPubSubServer
00077 {
00078     if (self = [super init])
00079     {
00080         _connection                 = aConnection;
00081         _servers                    = [CPArray arrayWithObject:(aPubSubServer || [TNStropheJID stropheJIDWithString:@"pubsub." + [[aConnection JID] domain]])];
00082         _numberOfPromptedServers    = 0;
00083         _nodes                      = [CPArray array];
00084         _subscriptionBatches        = [CPDictionary dictionary];
00085         _unsubscriptionBatches      = [CPDictionary dictionary];
00086     }
00087 
00088     return self;
00089 }
00090 
00091 
00092 #pragma mark -
00093 #pragma mark Notification handlers
00094 
00098 - (void)_didSubscribeToNode:(CPNotification)aNotification
00099 {
00100     if (_delegate && [_delegate respondsToSelector:@selector(pubSubController:subscribedToNode:)])
00101         [_delegate pubSubController:self subscribedToNode:[aNotification object]]
00102 }
00103 
00107 - (void)_didUnsubscribeToNode:(CPNotification)aNotification
00108 {
00109     if (_delegate && [_delegate respondsToSelector:@selector(pubSubController:unsubscribedFromNode:)])
00110         [_delegate pubSubController:self unsubscribedFromNode:[aNotification object]]
00111 }
00112 
00115 - (void)_didBatchSubscribe:(CPNotification)aNotification
00116 {
00117     var node    = [aNotification object],
00118         batchID = [aNotification useInfo],
00119         batch   = [_subscriptionBatches valueForKey:batchID],
00120         params  = [CPDictionary dictionaryWithObject:batchID forKey:@"batchID"];
00121 
00122     [batch removeObjectIdenticalTo:[node name]];
00123 
00124     if ([batch count] === 0)
00125         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubBatchSubscribeCompleteNotification object:self userInfo:params];
00126 }
00127 
00130 - (void)_didBatchUnsubscribe:(CPNotification)aNotification
00131 {
00132     var node    = [aNotification object],
00133         batchID = [aNotification useInfo],
00134         batch   = [_unsubscriptionBatches valueForKey:batchID],
00135         params  = [CPDictionary dictionaryWithObject:batchID forKey:@"batchID"];
00136 
00137     [batch removeObjectIdenticalTo:[node name]];
00138 
00139     if ([batch count] === 0)
00140         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubBatchUnsubscribeCompleteNotification object:self userInfo:params];
00141 }
00142 
00143 
00144 #pragma mark -
00145 #pragma mark Utilities
00146 
00151 - (BOOL)containsServerJID:(TNStropheJID)aServerJID
00152 {
00153     for (var i = 0; i < [_servers count]; i++)
00154         if ([[_servers objectAtIndex:i] node] == [aServerJID node])
00155             return YES;
00156     return NO;
00157 }
00158 
00164 - (TNPubSubNode)nodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer
00165 {
00166     for (var i = 0; i < [_nodes count]; i++)
00167     {
00168         var node = [_nodes objectAtIndex:i];
00169 
00170         if (([node name] === aNodeName) && (!aServer || [[node server] equals:aServer]))
00171             return node;
00172     }
00173 
00174     return;
00175 }
00176 
00181 - (TNPubSubNode)nodeWithName:(CPString)aNodeName
00182 {
00183     return [self nodeWithName:aNodeName server:nil];
00184 }
00185 
00191 - (TNPubSubNode)findOrCreateNodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer
00192 {
00193     var node = [self nodeWithName:aNodeName server:aServer];
00194 
00195     if (![self containsServerJID:aServer])
00196         [_servers addObject:aServer];
00197 
00198     if (!node)
00199     {
00200         node = [TNPubSubNode pubSubNodeWithNodeName:aNodeName connection:_connection pubSubServer:aServer];
00201         [_nodes addObject:node];
00202     }
00203     return node;
00204 }
00205 
00206 #pragma mark -
00207 #pragma mark Subscription Management
00208 
00212 - (void)retrieveSubscriptions
00213 {
00214     _numberOfPromptedServers = 0;
00215 
00216     for (var i = 0; i < [_servers count]; i++)
00217     {
00218         var uid     = [_connection getUniqueId],
00219             stanza  = [TNStropheStanza iqWithAttributes:{"type": "get", "to": [_servers objectAtIndex:i], "id": uid}],
00220             params  = [CPDictionary dictionaryWithObjectsAndKeys:uid,@"id"];
00221 
00222         [stanza addChildWithName:@"pubsub" andAttributes:{"xmlns": Strophe.NS.PUBSUB}];
00223         [stanza addChildWithName:@"subscriptions"];
00224 
00225         [_connection registerSelector:@selector(_didRetrieveSubscriptions:) ofObject:self withDict:params];
00226 
00227         [_connection send:stanza];
00228     }
00229 }
00230 
00233 - (BOOL)_didRetrieveSubscriptions:(TNStropheStanza)aStanza
00234 {
00235     if ([aStanza type] == @"result")
00236     {
00237         var subscriptions   = [aStanza childrenWithName:@"subscription"],
00238             server          = [aStanza from];
00239 
00240         for (var i = 0; i < [subscriptions count]; i++)
00241         {
00242             var subscription    = [subscriptions objectAtIndex:i],
00243                 nodeName        = [subscription valueForAttribute:@"node"],
00244                 subid           = [subscription valueForAttribute:@"subid"],
00245                 node            = [self findOrCreateNodeWithName:nodeName server:server];
00246 
00247             [node addSubscriptionID:subid];
00248 
00249             [[CPNotificationCenter defaultCenter] addObserver:self
00250                                                      selector:@selector(_didSubscribeToNode:)
00251                                                          name:TNStrophePubSubNodeSubscribedNotification
00252                                                        object:node];
00253 
00254             [[CPNotificationCenter defaultCenter] addObserver:self
00255                                                      selector:@selector(_didUnsubscribeToNode:)
00256                                                          name:TNStrophePubSubNodeUnsubscribedNotification
00257                                                        object:node];
00258         }
00259 
00260         _numberOfPromptedServers++;
00261 
00262         if (_numberOfPromptedServers >= [_servers count])
00263         {
00264             _numberOfPromptedServers = 0;
00265 
00266             [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubSubscriptionsRetrievedNotification object:self];
00267             if (_delegate && [_delegate respondsToSelector:@selector(pubSubController:retrievedSubscriptions:)])
00268                 [_delegate pubSubController:self retrievedSubscriptions:YES];
00269         }
00270     }
00271     else
00272     {
00273         if (_delegate && [_delegate respondsToSelector:@selector(pubSubController:retrievedSubscriptions:)])
00274             [_delegate pubSubController:self retrievedSubscriptions:NO];
00275         CPLog.error("Cannot retrieve the contents of pubsub node");
00276         CPLog.error(aStanza);
00277     }
00278 
00279 
00280     return NO;
00281 }
00282 
00288 - (TNPubSubNode)subscribeToNodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer nodeDelegate:(id)nodeDelegate
00289 {
00290     var node = [self findOrCreateNodeWithName:aNodeName server:aServer];
00291 
00292     [node setDelegate:nodeDelegate];
00293     [node subscribe];
00294 
00295     return node;
00296 }
00297 
00302 - (TNPubSubNode)subscribeToNodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer
00303 {
00304     return [self subscribeToNodeWithName:aNodeName server:aServer nodeDelegate:nil];
00305 }
00306 
00312 - (CPString)subscribeToNodesWithNames:(CPDictionary)someNodes nodesDelegate:(id)aDelegate
00313 {
00314     var batchID = [_connection getUniqueId],
00315         servers = [someNodes allKeys];
00316 
00317     [_subscriptionBatches setValue:someNodes forKey:batchID];
00318 
00319     for (var k = 0; k < [servers count]; k++)
00320     {
00321         var server = [servers objectAtIndex:k],
00322             nodes = [servers valueForKey:server];
00323 
00324         for (var i = 0; i < [nodes count]; i++)
00325         {
00326             var nodeName    = [nodes objectAtIndex:i],
00327                 node        = [self subscribeToNodeWithName:nodeName server:server nodeDelegate:aDelegate];
00328 
00329             [[CPNotificationCenter defaultCenter] addObserver:self
00330                                                      selector:@selector(_didBatchSubscribe:)
00331                                                          name:TNStrophePubSubNodeSubscribedNotification
00332                                                        object:node
00333                                                      userInfo:batchID];
00334         }
00335     }
00336 
00337     return batchID;
00338 }
00339 
00345 - (TNPubSubNode)unsubscribeFromNodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer nodeDelegate:(id)nodeDelegate
00346 {
00347     var node = [self findOrCreateNodeWithName:aNodeName server:aServer];
00348 
00349     [_nodes removeObject:node];
00350     [node setDelegate:nodeDelegate];
00351     [node unsubscribe];
00352 
00353     return node;
00354 }
00355 
00360 - (TNPubSubNode)unsubscribeFromNodeWithName:(CPString)aNodeName server:(TNStropheJID)aServer
00361 {
00362     return [self unsubscribeFromNodeWithName:aNodeName server:aServer nodeDelegate:nil];
00363 }
00364 
00370 - (CPString)unsubscribeFromNodesWithNames:(CPDictionary)someNodes nodesDelegate:(id)aDelegate
00371 {
00372     var batchID = [_connection getUniqueId],
00373         servers = [someNodes allKeys];
00374 
00375     [_unsubscriptionBatches setValue:someNodes forKey:batchID];
00376 
00377     for (var k = 0; k < [servers count]; k++)
00378     {
00379         var server = [servers objectAtIndex:k],
00380             nodes = [servers valueForKey:server];
00381 
00382         for (var i = 0; i < [nodes count]; i++)
00383         {
00384             var nodeName    = [nodes objectAtIndex:i],
00385                 node        = [self unsubscribeFromNodeWithName:nodeName server:server nodeDelegate:aDelegate];
00386 
00387             [[CPNotificationCenter defaultCenter] addObserver:self
00388                                                      selector:@selector(_didBatchUnsubscribe:)
00389                                                          name:TNStrophePubSubNodeUnsubscribedNotification
00390                                                        object:node
00391                                                      userInfo:batchID];
00392         }
00393     }
00394 
00395     return batchID;
00396 }
00397 
00400 - (void)unsubscribeFromAllNodes
00401 {
00402     for (var i = 0; i < [_nodes count]; i++)
00403         [[_nodes objectAtIndex:i] unsubscribe];
00404     [_nodes removeAllObjects];
00405 }
00406 
00407 @end
00408 
00409 @implementation TNPubSubController (CPSynthesizedAccessors)
00410 
00414 - (CPArray)nodes
00415 {
00416     return _nodes;
00417 }
00418 
00422 - (CPArray)servers
00423 {
00424     return _servers;
00425 }
00426 
00430 - (void)setServers:(CPArray)aValue
00431 {
00432     _servers = aValue;
00433 }
00434 
00438 - (id)delegate
00439 {
00440     return _delegate;
00441 }
00442 
00446 - (void)setDelegate:(id)aValue
00447 {
00448     _delegate = aValue;
00449 }
00450 
00451 @end
 All Classes Namespaces Files Functions Variables