Improved refresh mechanism.
[pithos-macos] / pithos-macos / PithosContainerNode.m
index 989ca1a..8e1679c 100644 (file)
 #import "PithosObjectNode.h"
 #import "PithosSubdirNode.h"
 #import "ASIPithosContainerRequest.h"
+#import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
 
 static NSImage *sharedIcon = nil;
 
 @implementation PithosContainerNode
+@synthesize pithosContainer;
 
 + (void)initialize {
        if (self == [PithosContainerNode class])
@@ -57,7 +59,6 @@ static NSImage *sharedIcon = nil;
 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
     if ((self = [super init])) {
         pithosContainer = [aPithosContainer retain];
-        refreshing = NO;
         prefix = nil;
         icon = [anIcon retain];
         childrenUpdatedNotificationName = @"PithosContainerNodeChildrenUpdated";
@@ -80,6 +81,8 @@ static NSImage *sharedIcon = nil;
 }
 
 - (void)dealloc {
+    [containerRequest clearDelegatesAndCancel];
+    [containerRequest release];
     [childrenUpdatedNotificationName release];
     [prefix release];
     [objects release];
@@ -90,7 +93,7 @@ static NSImage *sharedIcon = nil;
 #pragma mark -
 #pragma mark ASIHTTPRequestDelegate
 
-- (void)requestFinished:(ASIPithosContainerRequest *)containerRequest {
+- (void)requestFinished:(ASIHTTPRequest *)request {
     NSLog(@"URL: %@", [containerRequest url]);
     NSLog(@"cached: %d", [containerRequest didUseCachedResponse]);
 
@@ -104,62 +107,78 @@ static NSImage *sharedIcon = nil;
         if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
             // Save new children
             NSLog(@"using newChildren");
-            NSMutableArray *newChildren = [NSMutableArray array];
+            newChildren = [[NSMutableArray alloc] init];
             for (ASIPithosObject *object in objects) {
                 if (object.subdir) {
                     PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
                     if (children) {
                         NSUInteger oldIndex = [children indexOfObject:node];
-                        if (oldIndex != NSNotFound)
+                        if (oldIndex != NSNotFound) {
                             // Use the same pointer value, if possible
                             node = [children objectAtIndex:oldIndex];
+                            node.pithosContainer = pithosContainer;
+                            node.pithosObject = object;
+                        }
                     }
-                    [newChildren addObject:node];                
-                } else {
+                    [newChildren addObject:node];
+                } else if (([self class] != [PithosSubdirNode class]) || (![((PithosSubdirNode *)self).pithosObject.name isEqualToString:object.name])) {
+                    // XXX the if above removes false objects due to trailing slash
+                    // XXX this will change in the server, but it is fixed in the client for now
                     PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
                     if (children) {
                         NSUInteger oldIndex = [children indexOfObject:node];
-                        if (oldIndex != NSNotFound)
+                        if (oldIndex != NSNotFound) {
                             // Use the same pointer value, if possible
                             node = [children objectAtIndex:oldIndex];
+                            node.pithosContainer = pithosContainer;
+                            node.pithosObject = object;
+                        }
                     }
                     [newChildren addObject:node];                                
                 }
             }
-            [children release];
-            children = [newChildren retain];
         }
-        // Else cache was used and all results were fetched during this request, so previousChildren can be reused
+        // Else cache was used and all results were fetched during this request, so existing children can be reused
+        [containerRequest release];
+        containerRequest = nil;
         [objects release];
         objects = nil;
-        // XXX sort then based on preferences
-        refreshing = NO;
+        // XXX sort children based on preferences
+        @synchronized(self) {
+            freshness = PithosNodeStateRefreshFinished;
+        }
         // Notify observers that children are updated
         [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
     } else {
+        [containerRequest release];
         // Do an additional request to fetch more objects
-        ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                                                  limit:0 
-                                                                                                                 marker:[[someObjects lastObject] name] 
-                                                                                                                 prefix:prefix 
-                                                                                                              delimiter:@"/" 
-                                                                                                                   path:nil 
-                                                                                                                   meta:nil 
-                                                                                                                 shared:NO 
-                                                                                                                  until:nil];
-        newContainerRequest.delegate = self;
-        newContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [newContainerRequest startAsynchronous];
+        containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
+                                                                                     limit:0 
+                                                                                    marker:[[someObjects lastObject] name] 
+                                                                                    prefix:prefix 
+                                                                                 delimiter:@"/" 
+                                                                                      path:nil 
+                                                                                      meta:nil 
+                                                                                    shared:NO 
+                                                                                     until:nil] retain];
+        containerRequest.delegate = self;
+        containerRequest.downloadCache = [ASIDownloadCache sharedCache];
+        [containerRequest startAsynchronous];
     }
 }
 
-- (void)requestFailed:(ASIPithosContainerRequest *)containerRequest {
+- (void)requestFailed:(ASIHTTPRequest *)request {
     // XXX do something on error, cleanup
     NSLog(@"error:%@", [containerRequest error]);
+    [newChildren release];
+    newChildren = nil;
+    [containerRequest release];
+    containerRequest = nil;
     [objects release];
     objects = nil;
-    childrenDirty = YES;
-    refreshing = NO;
+    @synchronized(self) {
+        freshness = PithosNodeStateRefreshNeeded;
+    }
 }
 
 #pragma mark -
@@ -172,27 +191,39 @@ static NSImage *sharedIcon = nil;
 }
 
 - (NSArray *)children {
-    if (childrenDirty) {
-        @synchronized (self) {
-            if (!refreshing) {
-                refreshing = YES;
-                childrenDirty = NO;
-                ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                                                       limit:0 
-                                                                                                                      marker:nil 
-                                                                                                                      prefix:prefix 
-                                                                                                                   delimiter:@"/" 
-                                                                                                                        path:nil 
-                                                                                                                        meta:nil 
-                                                                                                                      shared:NO 
-                                                                                                                       until:nil];
+    @synchronized(self) {
+        switch (freshness) {
+            case PithosNodeStateFresh:
+                break;
+            case PithosNodeStateRefreshNeeded:
+                freshness = PithosNodeStateRefreshing;
+                containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
+                                                                                             limit:0 
+                                                                                            marker:nil 
+                                                                                            prefix:prefix 
+                                                                                         delimiter:@"/" 
+                                                                                              path:nil 
+                                                                                              meta:nil 
+                                                                                            shared:NO 
+                                                                                             until:nil] retain];
                 containerRequest.delegate = self;
                 containerRequest.downloadCache = [ASIDownloadCache sharedCache];
                 [containerRequest startAsynchronous];
-            }
+                break;
+            case PithosNodeStateRefreshing:
+                break;
+            case PithosNodeStateRefreshFinished:
+                if (newChildren) {
+                    [children release];
+                    children = newChildren;
+                    newChildren = nil;
+                }
+                freshness = PithosNodeStateFresh;
+            default:
+                break;
         }
+        return children;
     }
-    return children;
 }
 
 - (NSString *)displayName {