Support changes in container and object metadata.
[pithos-macos] / pithos-macos / PithosContainerNode.m
index 0fa0e2a..eb695c0 100644 (file)
@@ -2,7 +2,7 @@
 //  PithosContainerNode.m
 //  pithos-macos
 //
-// Copyright 2011 GRNET S.A. All rights reserved.
+// Copyright 2011-2012 GRNET S.A. All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or
 // without modification, are permitted provided that the following
 #import "PithosContainerNode.h"
 #import "PithosObjectNode.h"
 #import "PithosSubdirNode.h"
+#import "ASIPithos.h"
 #import "ASIPithosContainerRequest.h"
 #import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
-#import "PithosFileUtilities.h"
+#import "PithosUtilities.h"
 #import "PithosContainerNodeInfoController.h"
+#import "PithosActivityFacility.h"
 
 static NSImage *sharedIcon = nil;
 
 @implementation PithosContainerNode
-@synthesize pithosContainer, prefix;
+@synthesize pithos, pithosContainer, prefix;
 @synthesize policyVersioning, policyQuota;
 
 + (void)initialize {
@@ -59,8 +61,9 @@ static NSImage *sharedIcon = nil;
 #pragma mark -
 #pragma mark Object Lifecycle
 
-- (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
+- (id)initWithPithos:(ASIPithos *)aPithos pithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
     if ((self = [super init])) {
+        self.pithos = aPithos;
         self.pithosContainer = aPithosContainer;
         prefix = nil;
         self.icon = anIcon;
@@ -69,18 +72,18 @@ static NSImage *sharedIcon = nil;
     return self;
 }
 
-- (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer {
-    return [self initWithPithosContainer:aPithosContainer icon:nil];
+- (id)initWithPithos:(ASIPithos *)aPithos pithosContainer:(ASIPithosContainer *)aPithosContainer {
+    return [self initWithPithos:aPithos pithosContainer:aPithosContainer icon:nil];
 }
 
-- (id)initWithContainerName:(NSString *)aContainerName icon:(NSImage *)anIcon {
+- (id)initWithPithos:(ASIPithos *)aPithos containerName:(NSString *)aContainerName icon:(NSImage *)anIcon {
     ASIPithosContainer *container = [ASIPithosContainer container];
     container.name = aContainerName;
-    return [self initWithPithosContainer:container icon:anIcon];
+    return [self initWithPithos:aPithos pithosContainer:container icon:anIcon];
 }
 
-- (id)initWithContainerName:(NSString *)aContainerName {
-    return [self initWithContainerName:aContainerName icon:nil];
+- (id)initWithPithos:(ASIPithos *)aPithos containerName:(NSString *)aContainerName {
+    return [self initWithPithos:aPithos containerName:aContainerName icon:nil];
 }
 
 - (void)dealloc {
@@ -96,16 +99,26 @@ static NSImage *sharedIcon = nil;
     [prefix release];
     [objects release];
     [pithosContainer release];
+    [pithos release];
     [super dealloc];
 }
 
 #pragma mark -
 #pragma mark Properties
 
+- (void)setPithos:(ASIPithos *)aPithos {
+    if (aPithos && ![aPithos isEqualTo:pithos]) {
+        [pithos release];
+        pithos = [aPithos retain];
+        [url release];
+        url = nil;
+    }
+}
+
 - (NSString *)url {
     if (url == nil)
         url = [[NSString alloc] initWithFormat:@"%@/%@%@", 
-               (sharingAccount ? [ASIPithosRequest storageURLWithAuthUser:sharingAccount] : [ASIPithosRequest storageURL]), 
+               (sharingAccount ? [pithos storageURLWithAuthUser:sharingAccount] : pithos.storageURL), 
                pithosContainer.name, 
                (shared ? @"?shared" : @"")];
     return url;
@@ -118,23 +131,30 @@ static NSImage *sharedIcon = nil;
                 break;
             case PithosNodeStateRefreshNeeded:
                 freshness = PithosNodeStateRefreshing;
-                containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                             limit:0 
-                                                                                            marker:nil 
-                                                                                            prefix:prefix 
-                                                                                         delimiter:@"/" 
-                                                                                              path:nil 
-                                                                                              meta:nil 
-                                                                                            shared:shared 
-                                                                                             until:nil] retain];
+                containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithPithos:pithos 
+                                                                              containerName:pithosContainer.name 
+                                                                                      limit:0 
+                                                                                     marker:nil 
+                                                                                     prefix:prefix 
+                                                                                  delimiter:@"/" 
+                                                                                       path:nil 
+                                                                                       meta:nil 
+                                                                                     shared:shared 
+                                                                                      until:nil] retain];
                 if (sharingAccount)
-                    [containerRequest setRequestUserFromDefaultTo:sharingAccount];
+                    [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
                 containerRequest.delegate = self;
-                containerRequest.didFinishSelector = @selector(containerRequestFinished:);
-                containerRequest.didFailSelector = @selector(containerRequestFailed:);
+                containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+                containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+                containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                             [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
+                                             [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                                             NSStringFromSelector(@selector(containerRequestFinished:)), @"didFinishSelector", 
+                                             NSStringFromSelector(@selector(containerRequestFailed:)), @"didFailSelector", 
+                                             nil];
                 if (!forcedRefresh)
                     containerRequest.downloadCache = [ASIDownloadCache sharedCache];
-                [containerRequest startAsynchronous];
+                [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                 break;
             case PithosNodeStateRefreshing:
                 break;
@@ -185,41 +205,115 @@ static NSImage *sharedIcon = nil;
     }
 }
 
+- (void)setLimitedPithosContainer:(ASIPithosContainer *)aPithosContainer {
+    if (![pithosContainer isEqualTo:aPithosContainer]) {
+        self.pithosContainer.name = aPithosContainer.name;
+        self.pithosContainer.count = aPithosContainer.count;
+        self.pithosContainer.bytes = aPithosContainer.bytes;
+        self.pithosContainer.lastModified = aPithosContainer.lastModified;
+        self.pithosContainer.untilTimestamp = aPithosContainer.untilTimestamp;
+        if (!pithosNodeInfoController) {
+            self.pithosContainer.policy = aPithosContainer.policy;
+            self.pithosContainer = pithosContainer;
+        }
+    }
+}
+
 #pragma mark -
 #pragma mark ASIHTTPRequestDelegate
 
-- (void)containerRequestFinished:(ASIPithosContainerRequest *)request {
-    NSLog(@"URL: %@", [containerRequest url]);
-    NSLog(@"cached: %d", [containerRequest didUseCachedResponse]);
-    
-    if ((pithosContainer.blockHash == nil) || (pithosContainer.blockSize == 0)) {
-        pithosContainer.blockHash = [containerRequest blockHash];
-        pithosContainer.blockSize = [containerRequest blockSize];
-    }
-    
-    NSArray *someObjects = [containerRequest objects];
-    if (objects == nil) {
-        objects = [[NSMutableArray alloc] initWithArray:someObjects];
+- (void)containerRequestFailed:(ASIPithosContainerRequest *)request {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest];
+        [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        [containerRequest release];
+        containerRequest = newContainerRequest;
+        [[PithosUtilities prepareRequest:containerRequest priority:[[containerRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
     } else {
-        [objects addObjectsFromArray:someObjects];
+        NSString *message;
+        NSError *error = [containerRequest error];
+        if (error)
+            message = [NSString stringWithFormat:@"Container listing failed: %@", error];
+        else
+            message = [NSString stringWithFormat:@"Container listing failed: (%d) %@", 
+                       containerRequest.responseStatusCode, containerRequest.responseStatusMessage];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [[PithosActivityFacility defaultPithosActivityFacility] startAndEndActivityWithType:PithosActivityOther message:message];
+        });
+        [newChildren release];
+        newChildren = nil;
+        [containerRequest release];
+        containerRequest = nil;
+        [objects release];
+        objects = nil;
+        forcedRefresh = NO;
+        @synchronized(self) {
+            freshness = PithosNodeStateRefreshNeeded;
+        }
     }
-    if ([someObjects count] < 10000) {
-        if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
-            // Save new children
-            NSLog(@"using newChildren");
-            newChildren = [[NSMutableArray alloc] init];
-            NSArray *objectNames = [objects valueForKey:@"name"];
-            NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
-            BOOL isSubdirNode = ([self class] == [PithosSubdirNode class]);
-            for (ASIPithosObject *object in objects) {
-                if (!isSubdirNode || 
-                    [object.name hasPrefix:[((PithosSubdirNode *)self).prefix stringByAppendingString:@"/"]]) {
-                    // The check above removes false objects due to trailing slash or same prefix
-                    if (object.subdir) {
-                        NSUInteger sameNameObjectIndex = [objectNames indexOfObject:[object.name substringToIndex:([object.name length] - 1)]];
-                        if ((sameNameObjectIndex == NSNotFound) ||
-                            ![[[objects objectAtIndex:sameNameObjectIndex] contentType] isEqualToString:@"application/directory"]) {
-                            PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
+    [pool drain];
+}
+
+- (void)containerRequestFinished:(ASIPithosContainerRequest *)request {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    NSLog(@"List container finished: %@", [containerRequest url]);
+    NSLog(@"Cached: %d", [containerRequest didUseCachedResponse]);
+    if (containerRequest.responseStatusCode == 200) {
+        if ((pithosContainer.blockHash == nil) || (pithosContainer.blockSize == 0)) {
+            pithosContainer.blockHash = [containerRequest blockHash];
+            pithosContainer.blockSize = [containerRequest blockSize];
+        }
+    
+        NSArray *someObjects = [containerRequest objects];
+        if (objects == nil) {
+            objects = [[NSMutableArray alloc] initWithArray:someObjects];
+        } else {
+            [objects addObjectsFromArray:someObjects];
+        }
+        if ([someObjects count] < 10000) {
+            if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
+                // Save new children
+                NSLog(@"using newChildren");
+                newChildren = [[NSMutableArray alloc] init];
+                NSArray *objectNames = [objects valueForKey:@"name"];
+                NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
+                BOOL isSubdirNode = ([self class] == [PithosSubdirNode class]);
+                for (ASIPithosObject *object in objects) {
+                    if (!isSubdirNode || 
+                        ([object.name hasPrefix:[((PithosSubdirNode *)self).prefix stringByAppendingString:@"/"]] &&
+                         ([object.name length] > [((PithosSubdirNode *)self).prefix length] + 1))) {
+                        // The check above removes false objects due to trailing slash or same prefix
+                        if (object.subdir) {
+                            NSUInteger sameNameObjectIndex = [objectNames indexOfObject:[object.name substringToIndex:([object.name length] - 1)]];
+                            if ((sameNameObjectIndex == NSNotFound) || 
+                                ![PithosUtilities isContentTypeDirectory:[[objects objectAtIndex:sameNameObjectIndex] contentType]]) {
+                                PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithos:pithos 
+                                                                                   pithosContainer:pithosContainer 
+                                                                                      pithosObject:object] autorelease];
+                                node.parent = self;
+                                node.shared = shared;
+                                node.sharingAccount = sharingAccount;
+                                if (children) {
+                                    NSUInteger oldIndex = [children indexOfObject:node];
+                                    if (oldIndex != NSNotFound) {
+                                        // Use the same pointer value, if possible
+                                        node = [children objectAtIndex:oldIndex];
+                                        node.pithosContainer = pithosContainer;
+//                                        node.pithosObject = object;
+                                        [node setLimitedPithosObject:object];
+                                        [keptNodes addIndex:oldIndex];
+                                    }
+                                }
+                                if (sharingAccount)
+                                    node.pithosObject.allowedTo = [NSString stringWithString:@"read"];
+                                [newChildren addObject:node];
+                            }
+                        } else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
+                            PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithos:pithos 
+                                                                               pithosContainer:pithosContainer 
+                                                                                  pithosObject:object] autorelease];
                             node.parent = self;
                             node.shared = shared;
                             node.sharingAccount = sharingAccount;
@@ -229,57 +323,82 @@ static NSImage *sharedIcon = nil;
                                     // Use the same pointer value, if possible
                                     node = [children objectAtIndex:oldIndex];
                                     node.pithosContainer = pithosContainer;
-                                    node.pithosObject = object;
+//                                    node.pithosObject = object;
+                                    [node setLimitedPithosObject:object];
                                     [keptNodes addIndex:oldIndex];
                                 }
                             }
-                            if (sharingAccount)
-                                node.pithosObject.allowedTo = [NSString stringWithString:@"read"];
                             [newChildren addObject:node];
-                        }
-                    } else if ([object.contentType isEqualToString:@"application/directory"]) {
-                        PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
-                        node.parent = self;
-                        node.shared = shared;
-                        node.sharingAccount = sharingAccount;
-                        if (children) {
-                            NSUInteger oldIndex = [children indexOfObject:node];
-                            if (oldIndex != NSNotFound) {
-                                // Use the same pointer value, if possible
-                                node = [children objectAtIndex:oldIndex];
-                                node.pithosContainer = pithosContainer;
-                                node.pithosObject = object;
-                                [keptNodes addIndex:oldIndex];
-                            }
-                        }
-                        [newChildren addObject:node];
-                    } else {
-                        PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
-                        node.parent = self;
-                        node.shared = shared;
-                        node.sharingAccount = sharingAccount;
-                        if (children) {
-                            NSUInteger oldIndex = [children indexOfObject:node];
-                            if (oldIndex != NSNotFound) {
-                                // Use the same pointer value, if possible
-                                node = [children objectAtIndex:oldIndex];
-                                node.pithosContainer = pithosContainer;
-                                node.pithosObject = object;
-                                [keptNodes addIndex:oldIndex];
+                        } else {
+                            PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithos:pithos 
+                                                                               pithosContainer:pithosContainer 
+                                                                                  pithosObject:object] autorelease];
+                            node.parent = self;
+                            node.shared = shared;
+                            node.sharingAccount = sharingAccount;
+                            if (children) {
+                                NSUInteger oldIndex = [children indexOfObject:node];
+                                if (oldIndex != NSNotFound) {
+                                    // Use the same pointer value, if possible
+                                    node = [children objectAtIndex:oldIndex];
+                                    node.pithosContainer = pithosContainer;
+//                                    node.pithosObject = object;
+                                    [node setLimitedPithosObject:object];
+                                    [keptNodes addIndex:oldIndex];
+                                }
                             }
+                            [newChildren addObject:node];                                
                         }
-                        [newChildren addObject:node];                                
                     }
                 }
+                [[children objectsAtIndexes:
+                  [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
+                    if ([keptNodes containsIndex:idx])
+                        return NO;
+                    return YES;
+                }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
+            }
+            // 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;
+            forcedRefresh = NO;
+            @synchronized(self) {
+                freshness = PithosNodeStateRefreshFinished;
             }
-            [[children objectsAtIndexes:
-              [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
-                if ([keptNodes containsIndex:idx])
-                    return NO;
-                return YES;
-            }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
+            // Notify observers that children are updated
+            [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
+        } else {
+            [containerRequest release];
+            // Do an additional request to fetch more objects
+            containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithPithos:pithos 
+                                                                          containerName:pithosContainer.name 
+                                                                                  limit:0 
+                                                                                 marker:[[someObjects lastObject] name] 
+                                                                                 prefix:prefix 
+                                                                              delimiter:@"/" 
+                                                                                   path:nil 
+                                                                                   meta:nil 
+                                                                                 shared:shared 
+                                                                                  until:nil] retain];
+            if (sharingAccount)
+                [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
+            containerRequest.delegate = self;
+            containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+            containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+            containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                         [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
+                                         [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                                         NSStringFromSelector(@selector(containerRequestFinished:)), @"didFinishSelector", 
+                                         NSStringFromSelector(@selector(containerRequestFailed:)), @"didFailSelector", 
+                                         nil];
+            if (!forcedRefresh)
+            containerRequest.downloadCache = [ASIDownloadCache sharedCache];
+            [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
         }
-        // Else cache was used and all results were fetched during this request, so existing children can be reused
+    } else if (containerRequest.responseStatusCode == 304) {
+        // Container is not modified, so existing children can be reused
         [containerRequest release];
         containerRequest = nil;
         [objects release];
@@ -291,41 +410,13 @@ static NSImage *sharedIcon = nil;
         // Notify observers that children are updated
         [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
     } else {
-        [containerRequest release];
-        // Do an additional request to fetch more objects
-        containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                     limit:0 
-                                                                                    marker:[[someObjects lastObject] name] 
-                                                                                    prefix:prefix 
-                                                                                 delimiter:@"/" 
-                                                                                      path:nil 
-                                                                                      meta:nil 
-                                                                                    shared:shared 
-                                                                                     until:nil] retain];
-        if (sharingAccount)
-            [containerRequest setRequestUserFromDefaultTo:sharingAccount];
-        containerRequest.delegate = self;
-        if (!forcedRefresh)
-        containerRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [containerRequest startAsynchronous];
-    }
-}
-
-- (void)containerRequestFailed:(ASIPithosContainerRequest *)request {
-    [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
-    [newChildren release];
-    newChildren = nil;
-    [containerRequest release];
-    containerRequest = nil;
-    [objects release];
-    objects = nil;
-    forcedRefresh = NO;
-    @synchronized(self) {
-        freshness = PithosNodeStateRefreshNeeded;
+        [self containerRequestFailed:containerRequest];
     }
+    [pool drain];
 }
 
 - (void)containerMetadataRequestFinished:(ASIPithosContainerRequest *)request {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSLog(@"URL: %@", [request url]);
     NSLog(@"cached: %d", [request didUseCachedResponse]);
     
@@ -343,22 +434,47 @@ static NSImage *sharedIcon = nil;
             refreshMetadataContainerRequest = nil;
         }
     }
+    [pool drain];
 }
 
 - (void)containerMetadataRequestFailed:(ASIPithosContainerRequest *)request {
-    if ([request isEqualTo:applyMetadataContainerRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
-        @synchronized(self) {
-            [applyMetadataContainerRequest release];
-            applyMetadataContainerRequest = nil;
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
+    if (retries > 0) {
+        ASIPithosContainerRequest *newRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:request];
+        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
+        if ([request isEqualTo:applyMetadataContainerRequest]) {
+            @synchronized(self) {
+                [applyMetadataContainerRequest release];
+                applyMetadataContainerRequest = newRequest;
+            }
+        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
+            @synchronized(self) {
+                [refreshMetadataContainerRequest release];
+                refreshMetadataContainerRequest = newRequest;
+            }
         }
-    } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
-        [PithosFileUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
-        @synchronized(self) {
-            [refreshMetadataContainerRequest release];
-            refreshMetadataContainerRequest = nil;
+        [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
+    } else {
+        if ([request isEqualTo:applyMetadataContainerRequest]) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
+            });
+            @synchronized(self) {
+                [applyMetadataContainerRequest release];
+                applyMetadataContainerRequest = nil;
+            }
+        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
+            });
+            @synchronized(self) {
+                [refreshMetadataContainerRequest release];
+                refreshMetadataContainerRequest = nil;
+            }
         }
     }
+    [pool drain];
 }
 
 #pragma mark -
@@ -368,17 +484,24 @@ static NSImage *sharedIcon = nil;
     @synchronized(self) {
         if (applyMetadataContainerRequest == nil) {
             [[pithosNodeInfoController window] makeFirstResponder:nil];
-            applyMetadataContainerRequest = [[ASIPithosContainerRequest updateContainerMetadataRequestWithContainerName:pithosContainer.name 
-                                                                                                                 policy:[NSDictionary dictionaryWithObjectsAndKeys:
-                                                                                                                         policyVersioning, @"versioning", 
-                                                                                                                         [policyQuota stringValue], @"quota", 
-                                                                                                                         nil] 
-                                                                                                               metadata:pithosContainer.metadata 
-                                                                                                                 update:NO] retain];
+            applyMetadataContainerRequest = [[ASIPithosContainerRequest updateContainerMetadataRequestWithPithos:pithos 
+                                                                                                   containerName:pithosContainer.name 
+                                                                                                          policy:[NSDictionary dictionaryWithObjectsAndKeys:
+                                                                                                                  policyVersioning, @"versioning", 
+                                                                                                                  [policyQuota stringValue], @"quota", 
+                                                                                                                  nil] 
+                                                                                                        metadata:pithosContainer.metadata 
+                                                                                                          update:NO] retain];
             applyMetadataContainerRequest.delegate = self;
-            applyMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:);
-            applyMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:);
-            [applyMetadataContainerRequest startAsynchronous];
+            applyMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+            applyMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+            applyMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
+                                                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                                                      NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
+                                                      NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
+                                                      nil];
+            [[PithosUtilities prepareRequest:applyMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
@@ -386,12 +509,19 @@ static NSImage *sharedIcon = nil;
 - (void)refreshInfo {
     @synchronized(self) {
         if (refreshMetadataContainerRequest == nil) {
-            refreshMetadataContainerRequest = [[ASIPithosContainerRequest containerMetadataRequestWithContainerName:pithosContainer.name] retain];
+            refreshMetadataContainerRequest = [[ASIPithosContainerRequest containerMetadataRequestWithPithos:pithos 
+                                                                                               containerName:pithosContainer.name] retain];
             refreshMetadataContainerRequest.delegate = self;
-            refreshMetadataContainerRequest.didFinishSelector = @selector(containerMetadataRequestFinished:);
-            refreshMetadataContainerRequest.didFailSelector = @selector(containerMetadataRequestFailed:);
+            refreshMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
+            refreshMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
+            refreshMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+                                                        [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
+                                                        [NSNumber numberWithUnsignedInteger:10], @"retries", 
+                                                        NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
+                                                        NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
+                                                        nil];
             refreshMetadataContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
-            [refreshMetadataContainerRequest startAsynchronous];
+            [[PithosUtilities prepareRequest:refreshMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
         }
     }
 }
@@ -400,8 +530,10 @@ static NSImage *sharedIcon = nil;
 #pragma mark Actions
 
 - (void)showPithosNodeInfo:(id)sender {
-    if (!pithosNodeInfoController)
+    if (!pithosNodeInfoController) {
         pithosNodeInfoController = [[PithosContainerNodeInfoController alloc] initWithPithosNode:self];
+        [self refreshInfo];
+    }
     [pithosNodeInfoController showWindow:sender];
     [[pithosNodeInfoController window] makeKeyAndOrderFront:sender];
     [NSApp activateIgnoringOtherApps:YES];