Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / PithosContainerNode.m @ d4433f6f

History | View | Annotate | Download (28 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
    }
71
    return self;
72
}
73

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

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

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

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

    
104
#pragma mark -
105
#pragma mark Properties
106

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

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

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

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

    
177
- (void)setDisplayName:(NSString *)aDisplayName {
178
}
179

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

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

    
206
- (void)setLimitedPithosContainer:(ASIPithosContainer *)aPithosContainer {
207
    if (![pithosContainer isEqualTo:aPithosContainer]) {
208
        self.pithosContainer.name = aPithosContainer.name;
209
        self.pithosContainer.count = aPithosContainer.count;
210
        self.pithosContainer.bytes = aPithosContainer.bytes;
211
        self.pithosContainer.lastModified = aPithosContainer.lastModified;
212
        self.pithosContainer.untilTimestamp = aPithosContainer.untilTimestamp;
213
        if (!pithosNodeInfoController) {
214
            self.pithosContainer.policy = aPithosContainer.policy;
215
            self.pithosContainer = pithosContainer;
216
        }
217
    }
218
}
219

    
220
#pragma mark -
221
#pragma mark ASIHTTPRequestDelegate
222

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

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

    
417
- (void)containerMetadataRequestFinished:(ASIPithosContainerRequest *)request {
418
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
419
    NSLog(@"URL: %@", [request url]);
420
    NSLog(@"cached: %d", [request didUseCachedResponse]);
421
    
422
    if ([request isEqualTo:applyMetadataContainerRequest]) {
423
        @synchronized(self) {
424
            [applyMetadataContainerRequest release];
425
            applyMetadataContainerRequest = nil;
426
        }
427
        [self refreshInfo];
428
    } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
429
        [[pithosNodeInfoController window] makeFirstResponder:nil];
430
        self.pithosContainer = [refreshMetadataContainerRequest container];
431
        @synchronized(self) {
432
            [refreshMetadataContainerRequest release];
433
            refreshMetadataContainerRequest = nil;
434
        }
435
    }
436
    [pool drain];
437
}
438

    
439
- (void)containerMetadataRequestFailed:(ASIPithosContainerRequest *)request {
440
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
441
    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
442
    if (retries > 0) {
443
        ASIPithosContainerRequest *newRequest = (ASIPithosContainerRequest *)[[PithosUtilities copyRequest:request] autorelease];
444
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
445
        if ([request isEqualTo:applyMetadataContainerRequest]) {
446
            @synchronized(self) {
447
                [applyMetadataContainerRequest release];
448
                applyMetadataContainerRequest = newRequest;
449
            }
450
        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
451
            @synchronized(self) {
452
                [refreshMetadataContainerRequest release];
453
                refreshMetadataContainerRequest = newRequest;
454
            }
455
        }
456
        [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
457
    } else {
458
        if ([request isEqualTo:applyMetadataContainerRequest]) {
459
            dispatch_async(dispatch_get_main_queue(), ^{
460
                [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataContainerRequest];
461
            });
462
            @synchronized(self) {
463
                [applyMetadataContainerRequest release];
464
                applyMetadataContainerRequest = nil;
465
            }
466
        } else if ([request isEqualTo:refreshMetadataContainerRequest]) {
467
            dispatch_async(dispatch_get_main_queue(), ^{
468
                [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataContainerRequest];
469
            });
470
            @synchronized(self) {
471
                [refreshMetadataContainerRequest release];
472
                refreshMetadataContainerRequest = nil;
473
            }
474
        }
475
    }
476
    [pool drain];
477
}
478

    
479
#pragma mark -
480
#pragma mark Info
481

    
482
- (void)applyInfo {
483
    @synchronized(self) {
484
        if (applyMetadataContainerRequest == nil) {
485
            [[pithosNodeInfoController window] makeFirstResponder:nil];
486
            applyMetadataContainerRequest = [[ASIPithosContainerRequest updateContainerMetadataRequestWithPithos:pithos 
487
                                                                                                   containerName:pithosContainer.name 
488
                                                                                                          policy:[NSDictionary dictionaryWithObjectsAndKeys:
489
                                                                                                                  policyVersioning, @"versioning", 
490
                                                                                                                  [policyQuota stringValue], @"quota", 
491
                                                                                                                  nil] 
492
                                                                                                        metadata:pithosContainer.metadata 
493
                                                                                                          update:NO] retain];
494
            applyMetadataContainerRequest.delegate = self;
495
            applyMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
496
            applyMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
497
            applyMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
498
                                                      [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
499
                                                      [NSNumber numberWithUnsignedInteger:10], @"retries", 
500
                                                      NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
501
                                                      NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
502
                                                      nil];
503
            [[PithosUtilities prepareRequest:applyMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
504
        }
505
    }
506
}
507

    
508
- (void)refreshInfo {
509
    @synchronized(self) {
510
        if (refreshMetadataContainerRequest == nil) {
511
            refreshMetadataContainerRequest = [[ASIPithosContainerRequest containerMetadataRequestWithPithos:pithos 
512
                                                                                               containerName:pithosContainer.name] retain];
513
            refreshMetadataContainerRequest.delegate = self;
514
            refreshMetadataContainerRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
515
            refreshMetadataContainerRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
516
            refreshMetadataContainerRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
517
                                                        [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
518
                                                        [NSNumber numberWithUnsignedInteger:10], @"retries", 
519
                                                        NSStringFromSelector(@selector(containerMetadataRequestFinished:)), @"didFinishSelector", 
520
                                                        NSStringFromSelector(@selector(containerMetadataRequestFailed:)), @"didFailSelector", 
521
                                                        nil];
522
            refreshMetadataContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
523
            [[PithosUtilities prepareRequest:refreshMetadataContainerRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
524
        }
525
    }
526
}
527

    
528
#pragma mark -
529
#pragma mark Actions
530

    
531
- (void)showPithosNodeInfo:(id)sender {
532
    if (!pithosNodeInfoController) {
533
        pithosNodeInfoController = [[PithosContainerNodeInfoController alloc] initWithPithosNode:self];
534
        [self refreshInfo];
535
    }
536
    [pithosNodeInfoController showWindow:sender];
537
    [[pithosNodeInfoController window] makeKeyAndOrderFront:sender];
538
    [NSApp activateIgnoringOtherApps:YES];
539
}
540

    
541
@end