Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / PithosContainerNode.m @ d8426ffb

History | View | Annotate | Download (27.2 kB)

1
//
2
//  PithosContainerNode.m
3
//  pithos-macos
4
//
5
// Copyright 2011-2012 GRNET S.A. All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or
8
// without modification, are permitted provided that the following
9
// conditions are met:
10
// 
11
//   1. Redistributions of source code must retain the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer.
14
// 
15
//   2. Redistributions in binary form must reproduce the above
16
//      copyright notice, this list of conditions and the following
17
//      disclaimer in the documentation and/or other materials
18
//      provided with the distribution.
19
// 
20
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
// POSSIBILITY OF SUCH DAMAGE.
32
// 
33
// The views and conclusions contained in the software and
34
// documentation are those of the authors and should not be
35
// interpreted as representing official policies, either expressed
36
// or implied, of GRNET S.A.
37

    
38
#import "PithosContainerNode.h"
39
#import "PithosObjectNode.h"
40
#import "PithosSubdirNode.h"
41
#import "ASIPithos.h"
42
#import "ASIPithosContainerRequest.h"
43
#import "ASIPithosContainer.h"
44
#import "ASIPithosObject.h"
45
#import "ASIDownloadCache.h"
46
#import "PithosUtilities.h"
47
#import "PithosContainerNodeInfoController.h"
48
#import "PithosActivityFacility.h"
49

    
50
static NSImage *sharedIcon = nil;
51

    
52
@implementation PithosContainerNode
53
@synthesize pithos, pithosContainer, prefix;
54
@synthesize policyVersioning, policyQuota;
55

    
56
+ (void)initialize {
57
	if (self == [PithosContainerNode class])
58
        sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericHardDiskIcon)] retain];
59
}
60

    
61
#pragma mark -
62
#pragma mark Object Lifecycle
63

    
64
- (id)initWithPithos:(ASIPithos *)aPithos pithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
65
    if ((self = [super init])) {
66
        self.pithos = aPithos;
67
        self.pithosContainer = aPithosContainer;
68
        prefix = nil;
69
        self.icon = anIcon;
70
        childrenUpdatedNotificationName = @"PithosContainerNodeChildrenUpdated";
71
    }
72
    return self;
73
}
74

    
75
- (id)initWithPithos:(ASIPithos *)aPithos pithosContainer:(ASIPithosContainer *)aPithosContainer {
76
    return [self initWithPithos:aPithos pithosContainer:aPithosContainer icon:nil];
77
}
78

    
79
- (id)initWithPithos:(ASIPithos *)aPithos containerName:(NSString *)aContainerName icon:(NSImage *)anIcon {
80
    ASIPithosContainer *container = [ASIPithosContainer container];
81
    container.name = aContainerName;
82
    return [self initWithPithos:aPithos pithosContainer:container icon:anIcon];
83
}
84

    
85
- (id)initWithPithos:(ASIPithos *)aPithos containerName:(NSString *)aContainerName {
86
    return [self initWithPithos:aPithos containerName:aContainerName icon:nil];
87
}
88

    
89
- (void)dealloc {
90
    [containerRequest clearDelegatesAndCancel];
91
    [containerRequest release];
92
    [refreshMetadataContainerRequest clearDelegatesAndCancel];
93
    [refreshMetadataContainerRequest release];
94
    [applyMetadataContainerRequest clearDelegatesAndCancel];
95
    [applyMetadataContainerRequest release];
96
    [policyQuota release];
97
    [policyVersioning release];
98
    [childrenUpdatedNotificationName release];
99
    [prefix release];
100
    [objects release];
101
    [pithosContainer release];
102
    [pithos release];
103
    [super dealloc];
104
}
105

    
106
#pragma mark -
107
#pragma mark Properties
108

    
109
- (void)setPithos:(ASIPithos *)aPithos {
110
    if (aPithos && ![aPithos isEqualTo:pithos]) {
111
        [pithos release];
112
        pithos = [aPithos retain];
113
        [url release];
114
        url = nil;
115
    }
116
}
117

    
118
- (NSString *)url {
119
    if (url == nil)
120
        url = [[NSString alloc] initWithFormat:@"%@/%@%@", 
121
               (sharingAccount ? [pithos storageURLWithAuthUser:sharingAccount] : pithos.storageURL), 
122
               pithosContainer.name, 
123
               (shared ? @"?shared" : @"")];
124
    return url;
125
}
126

    
127
- (NSArray *)children {
128
    @synchronized(self) {
129
        switch (freshness) {
130
            case PithosNodeStateFresh:
131
                break;
132
            case PithosNodeStateRefreshNeeded:
133
                freshness = PithosNodeStateRefreshing;
134
                containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithPithos:pithos 
135
                                                                              containerName:pithosContainer.name 
136
                                                                                      limit:0 
137
                                                                                     marker:nil 
138
                                                                                     prefix:prefix 
139
                                                                                  delimiter:@"/" 
140
                                                                                       path:nil 
141
                                                                                       meta:nil 
142
                                                                                     shared:shared 
143
                                                                                      until:nil] retain];
144
                if (sharingAccount)
145
                    [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
146
                containerRequest.delegate = self;
147
                containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
148
                containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
149
                containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
150
                                             [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
151
                                             [NSNumber numberWithUnsignedInteger:10], @"retries", 
152
                                             NSStringFromSelector(@selector(containerRequestFinished:)), @"didFinishSelector", 
153
                                             NSStringFromSelector(@selector(containerRequestFailed:)), @"didFailSelector", 
154
                                             nil];
155
                if (!forcedRefresh)
156
                    containerRequest.downloadCache = [ASIDownloadCache sharedCache];
157
                [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
158
                break;
159
            case PithosNodeStateRefreshing:
160
                break;
161
            case PithosNodeStateRefreshFinished:
162
                if (newChildren) {
163
                    [children release];
164
                    children = newChildren;
165
                    newChildren = nil;
166
                }
167
                freshness = PithosNodeStateFresh;
168
            default:
169
                break;
170
        }
171
        return children;
172
    }
173
}
174

    
175
- (NSString *)displayName {
176
    return [[pithosContainer.name copy] autorelease];
177
}
178

    
179
- (void)setDisplayName:(NSString *)aDisplayName {
180
}
181

    
182
- (NSImage *)icon {
183
    if (icon == nil) {
184
        if ([pithosContainer.name isEqualToString:@"pithos"])
185
            icon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)] retain];
186
        else if ([pithosContainer.name isEqualToString:@"trash"])
187
            icon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)] retain];
188
        else
189
            icon = [sharedIcon retain];
190
    }
191
    return icon;
192
}
193

    
194
- (void)setPithosContainer:(ASIPithosContainer *)aPithosContainer {
195
    if (![pithosContainer isEqualTo:aPithosContainer]) {
196
        [pithosContainer release];
197
        pithosContainer = [aPithosContainer retain];
198
    }
199
    if (pithosContainer.policy) {
200
        self.policyVersioning = [pithosContainer.policy objectForKey:@"versioning"];
201
        self.policyQuota = [NSNumber numberWithLongLong:[[pithosContainer.policy objectForKey:@"quota"] longLongValue]];
202
    } else {
203
        self.policyVersioning = @"manual";
204
        self.policyQuota = [NSNumber numberWithLongLong:0];
205
    }
206
}
207

    
208
#pragma mark -
209
#pragma mark ASIHTTPRequestDelegate
210

    
211
- (void)containerRequestFailed:(ASIPithosContainerRequest *)request {
212
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
213
    NSUInteger retries = [[containerRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
214
    if (retries > 0) {
215
        ASIPithosContainerRequest *newContainerRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:containerRequest];
216
        [(NSMutableDictionary *)(newContainerRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
217
        [containerRequest release];
218
        containerRequest = newContainerRequest;
219
        [[PithosUtilities prepareRequest:containerRequest priority:[[containerRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
220
    } else {
221
        NSString *message;
222
        NSError *error = [containerRequest error];
223
        if (error)
224
            message = [NSString stringWithFormat:@"Container listing failed: %@", error];
225
        else
226
            message = [NSString stringWithFormat:@"Container listing failed: (%d) %@", 
227
                       containerRequest.responseStatusCode, containerRequest.responseStatusMessage];
228
        dispatch_async(dispatch_get_main_queue(), ^{
229
            [[PithosActivityFacility defaultPithosActivityFacility] startAndEndActivityWithType:PithosActivityOther message:message];
230
        });
231
        [newChildren release];
232
        newChildren = nil;
233
        [containerRequest release];
234
        containerRequest = nil;
235
        [objects release];
236
        objects = nil;
237
        forcedRefresh = NO;
238
        @synchronized(self) {
239
            freshness = PithosNodeStateRefreshNeeded;
240
        }
241
    }
242
    [pool drain];
243
}
244

    
245
- (void)containerRequestFinished:(ASIPithosContainerRequest *)request {
246
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
247
    NSLog(@"List container finished: %@", [containerRequest url]);
248
    NSLog(@"Cached: %d", [containerRequest didUseCachedResponse]);
249
    if (containerRequest.responseStatusCode == 200) {
250
        if ((pithosContainer.blockHash == nil) || (pithosContainer.blockSize == 0)) {
251
            pithosContainer.blockHash = [containerRequest blockHash];
252
            pithosContainer.blockSize = [containerRequest blockSize];
253
        }
254
    
255
        NSArray *someObjects = [containerRequest objects];
256
        if (objects == nil) {
257
            objects = [[NSMutableArray alloc] initWithArray:someObjects];
258
        } else {
259
            [objects addObjectsFromArray:someObjects];
260
        }
261
        if ([someObjects count] < 10000) {
262
            if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
263
                // Save new children
264
                NSLog(@"using newChildren");
265
                newChildren = [[NSMutableArray alloc] init];
266
                NSArray *objectNames = [objects valueForKey:@"name"];
267
                NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
268
                BOOL isSubdirNode = ([self class] == [PithosSubdirNode class]);
269
                for (ASIPithosObject *object in objects) {
270
                    if (!isSubdirNode || 
271
                        ([object.name hasPrefix:[((PithosSubdirNode *)self).prefix stringByAppendingString:@"/"]] &&
272
                         ([object.name length] > [((PithosSubdirNode *)self).prefix length] + 1))) {
273
                        // The check above removes false objects due to trailing slash or same prefix
274
                        if (object.subdir) {
275
                            NSUInteger sameNameObjectIndex = [objectNames indexOfObject:[object.name substringToIndex:([object.name length] - 1)]];
276
                            if ((sameNameObjectIndex == NSNotFound) || 
277
                                ![PithosUtilities isContentTypeDirectory:[[objects objectAtIndex:sameNameObjectIndex] contentType]]) {
278
                                PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithos:pithos 
279
                                                                                   pithosContainer:pithosContainer 
280
                                                                                      pithosObject:object] autorelease];
281
                                node.parent = self;
282
                                node.shared = shared;
283
                                node.sharingAccount = sharingAccount;
284
                                if (children) {
285
                                    NSUInteger oldIndex = [children indexOfObject:node];
286
                                    if (oldIndex != NSNotFound) {
287
                                        // Use the same pointer value, if possible
288
                                        node = [children objectAtIndex:oldIndex];
289
                                        node.pithosContainer = pithosContainer;
290
                                        node.pithosObject = object;
291
                                        [keptNodes addIndex:oldIndex];
292
                                    }
293
                                }
294
                                if (sharingAccount)
295
                                    node.pithosObject.allowedTo = [NSString stringWithString:@"read"];
296
                                [newChildren addObject:node];
297
                            }
298
                        } else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
299
                            PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithos:pithos 
300
                                                                               pithosContainer:pithosContainer 
301
                                                                                  pithosObject:object] autorelease];
302
                            node.parent = self;
303
                            node.shared = shared;
304
                            node.sharingAccount = sharingAccount;
305
                            if (children) {
306
                                NSUInteger oldIndex = [children indexOfObject:node];
307
                                if (oldIndex != NSNotFound) {
308
                                    // Use the same pointer value, if possible
309
                                    node = [children objectAtIndex:oldIndex];
310
                                    node.pithosContainer = pithosContainer;
311
                                    node.pithosObject = object;
312
                                    [keptNodes addIndex:oldIndex];
313
                                }
314
                            }
315
                            [newChildren addObject:node];
316
                        } else {
317
                            PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithos:pithos 
318
                                                                               pithosContainer:pithosContainer 
319
                                                                                  pithosObject:object] autorelease];
320
                            node.parent = self;
321
                            node.shared = shared;
322
                            node.sharingAccount = sharingAccount;
323
                            if (children) {
324
                                NSUInteger oldIndex = [children indexOfObject:node];
325
                                if (oldIndex != NSNotFound) {
326
                                    // Use the same pointer value, if possible
327
                                    node = [children objectAtIndex:oldIndex];
328
                                    node.pithosContainer = pithosContainer;
329
                                    node.pithosObject = object;
330
                                    [keptNodes addIndex:oldIndex];
331
                                }
332
                            }
333
                            [newChildren addObject:node];                                
334
                        }
335
                    }
336
                }
337
                [[children objectsAtIndexes:
338
                  [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
339
                    if ([keptNodes containsIndex:idx])
340
                        return NO;
341
                    return YES;
342
                }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
343
            }
344
            // Else cache was used and all results were fetched during this request, so existing children can be reused
345
            [containerRequest release];
346
            containerRequest = nil;
347
            [objects release];
348
            objects = nil;
349
            forcedRefresh = NO;
350
            @synchronized(self) {
351
                freshness = PithosNodeStateRefreshFinished;
352
            }
353
            // Notify observers that children are updated
354
            [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
355
        } else {
356
            [containerRequest release];
357
            // Do an additional request to fetch more objects
358
            containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithPithos:pithos 
359
                                                                          containerName:pithosContainer.name 
360
                                                                                  limit:0 
361
                                                                                 marker:[[someObjects lastObject] name] 
362
                                                                                 prefix:prefix 
363
                                                                              delimiter:@"/" 
364
                                                                                   path:nil 
365
                                                                                   meta:nil 
366
                                                                                 shared:shared 
367
                                                                                  until:nil] retain];
368
            if (sharingAccount)
369
                [containerRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
370
            containerRequest.delegate = self;
371
            containerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
372
            containerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
373
            containerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
374
                                         [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
375
                                         [NSNumber numberWithUnsignedInteger:10], @"retries", 
376
                                         NSStringFromSelector(@selector(containerRequestFinished:)), @"didFinishSelector", 
377
                                         NSStringFromSelector(@selector(containerRequestFailed:)), @"didFailSelector", 
378
                                         nil];
379
            if (!forcedRefresh)
380
            containerRequest.downloadCache = [ASIDownloadCache sharedCache];
381
            [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
382
        }
383
    } else if (containerRequest.responseStatusCode == 304) {
384
        // Container is not modified, so existing children can be reused
385
        [containerRequest release];
386
        containerRequest = nil;
387
        [objects release];
388
        objects = nil;
389
        forcedRefresh = NO;
390
        @synchronized(self) {
391
            freshness = PithosNodeStateRefreshFinished;
392
        }
393
        // Notify observers that children are updated
394
        [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
395
    } else {
396
        [self containerRequestFailed:containerRequest];
397
    }
398
    [pool drain];
399
}
400

    
401
- (void)containerMetadataRequestFinished:(ASIPithosContainerRequest *)request {
402
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
403
    NSLog(@"URL: %@", [request url]);
404
    NSLog(@"cached: %d", [request didUseCachedResponse]);
405
    
406
    if ([request isEqualTo:applyMetadataContainerRequest]) {
407
        @synchronized(self) {
408
            [applyMetadataContainerRequest release];
409
            applyMetadataContainerRequest = nil;
410
        }
411
        [self refreshInfo];
412
    } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
413
        [[pithosNodeInfoController window] makeFirstResponder:nil];
414
        self.pithosContainer = [refreshMetadataContainerRequest container];
415
        @synchronized(self) {
416
            [refreshMetadataContainerRequest release];
417
            refreshMetadataContainerRequest = nil;
418
        }
419
    }
420
    [pool drain];
421
}
422

    
423
- (void)containerMetadataRequestFailed:(ASIPithosContainerRequest *)request {
424
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
425
    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
426
    if (retries > 0) {
427
        ASIPithosContainerRequest *newRequest = (ASIPithosContainerRequest *)[PithosUtilities copyRequest:request];
428
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
429
        if ([request isEqualTo:applyMetadataContainerRequest]) {
430
            @synchronized(self) {
431
                [applyMetadataContainerRequest release];
432
                applyMetadataContainerRequest = newRequest;
433
            }
434
        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
435
            @synchronized(self) {
436
                [refreshMetadataContainerRequest release];
437
                refreshMetadataContainerRequest = newRequest;
438
            }
439
        }
440
        [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
441
    } else {
442
        if ([request isEqualTo:applyMetadataContainerRequest]) {
443
            dispatch_async(dispatch_get_main_queue(), ^{
444
                [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
445
            });
446
            @synchronized(self) {
447
                [applyMetadataContainerRequest release];
448
                applyMetadataContainerRequest = nil;
449
            }
450
        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
451
            dispatch_async(dispatch_get_main_queue(), ^{
452
                [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
453
            });
454
            @synchronized(self) {
455
                [refreshMetadataContainerRequest release];
456
                refreshMetadataContainerRequest = nil;
457
            }
458
        }
459
    }
460
    [pool drain];
461
}
462

    
463
#pragma mark -
464
#pragma mark Info
465

    
466
- (void)applyInfo {
467
    @synchronized(self) {
468
        if (applyMetadataContainerRequest == nil) {
469
            [[pithosNodeInfoController window] makeFirstResponder:nil];
470
            applyMetadataContainerRequest = [[ASIPithosContainerRequest updateContainerMetadataRequestWithPithos:pithos 
471
                                                                                                   containerName:pithosContainer.name 
472
                                                                                                          policy:[NSDictionary dictionaryWithObjectsAndKeys:
473
                                                                                                                  policyVersioning, @"versioning", 
474
                                                                                                                  [policyQuota stringValue], @"quota", 
475
                                                                                                                  nil] 
476
                                                                                                        metadata:pithosContainer.metadata 
477
                                                                                                          update:NO] retain];
478
            applyMetadataContainerRequest.delegate = self;
479
            applyMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
480
            applyMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
481
            applyMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
482
                                                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
483
                                                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
484
                                                      NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
485
                                                      NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
486
                                                      nil];
487
            [[PithosUtilities prepareRequest:applyMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
488
        }
489
    }
490
}
491

    
492
- (void)refreshInfo {
493
    @synchronized(self) {
494
        if (refreshMetadataContainerRequest == nil) {
495
            refreshMetadataContainerRequest = [[ASIPithosContainerRequest containerMetadataRequestWithPithos:pithos 
496
                                                                                               containerName:pithosContainer.name] retain];
497
            refreshMetadataContainerRequest.delegate = self;
498
            refreshMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
499
            refreshMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
500
            refreshMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
501
                                                        [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
502
                                                        [NSNumber numberWithUnsignedInteger:10], @"retries", 
503
                                                        NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
504
                                                        NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
505
                                                        nil];
506
            refreshMetadataContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
507
            [[PithosUtilities prepareRequest:refreshMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
508
        }
509
    }
510
}
511

    
512
#pragma mark -
513
#pragma mark Actions
514

    
515
- (void)showPithosNodeInfo:(id)sender {
516
    if (!pithosNodeInfoController)
517
        pithosNodeInfoController = [[PithosContainerNodeInfoController alloc] initWithPithosNode:self];
518
    [pithosNodeInfoController showWindow:sender];
519
    [[pithosNodeInfoController window] makeKeyAndOrderFront:sender];
520
    [NSApp activateIgnoringOtherApps:YES];
521
}
522

    
523
@end