// // PithosNode.m // pithos-macos // // Copyright 2011 GRNET S.A. All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the following // conditions are met: // // 1. Redistributions of source code must retain the above // copyright notice, this list of conditions and the following // disclaimer. // // 2. Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials // provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // The views and conclusions contained in the software and // documentation are those of the authors and should not be // interpreted as representing official policies, either expressed // or implied, of GRNET S.A. #import "PithosContainerNode.h" #import "PithosObjectNode.h" #import "PithosSubdirNode.h" #import "ASIPithosContainerRequest.h" #import "ASIPithosContainer.h" #import "ASIPithosObject.h" #import "ASIDownloadCache.h" static NSImage *sharedIcon = nil; @implementation PithosContainerNode @synthesize pithosContainer; + (void)initialize { if (self == [PithosContainerNode class]) sharedIcon = [[NSImage imageNamed:@"container"] retain]; } #pragma mark - #pragma mark Object Lifecycle - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon { if ((self = [super init])) { pithosContainer = [aPithosContainer retain]; prefix = nil; icon = [anIcon retain]; childrenUpdatedNotificationName = @"PithosContainerNodeChildrenUpdated"; } return self; } - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer { return [self initWithPithosContainer:aPithosContainer icon:nil]; } - (id)initWithContainerName:(NSString *)aContainerName icon:(NSImage *)anIcon { ASIPithosContainer *container = [ASIPithosContainer container]; container.name = aContainerName; return [self initWithPithosContainer:container icon:anIcon]; } - (id)initWithContainerName:(NSString *)aContainerName { return [self initWithContainerName:aContainerName icon:nil]; } - (void)dealloc { [containerRequest clearDelegatesAndCancel]; [containerRequest release]; [childrenUpdatedNotificationName release]; [prefix release]; [objects release]; [pithosContainer release]; [super dealloc]; } #pragma mark - #pragma mark ASIHTTPRequestDelegate - (void)requestFinished:(ASIHTTPRequest *)request { NSLog(@"URL: %@", [containerRequest url]); NSLog(@"cached: %d", [containerRequest didUseCachedResponse]); 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]; for (ASIPithosObject *object in objects) { if (object.subdir) { PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease]; if (children) { NSUInteger oldIndex = [children indexOfObject:node]; if (oldIndex != NSNotFound) { // Use the same pointer value, if possible node = [children objectAtIndex:oldIndex]; node.pithosContainer = pithosContainer; node.pithosObject = object; } } [newChildren addObject:node]; } else if (([self class] != [PithosSubdirNode class]) || (![((PithosSubdirNode *)self).pithosObject.name isEqualToString:object.name])) { // XXX the if above removes false objects due to trailing slash // XXX this will change in the server, but it is fixed in the client for now PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease]; if (children) { NSUInteger oldIndex = [children indexOfObject:node]; if (oldIndex != NSNotFound) { // Use the same pointer value, if possible node = [children objectAtIndex:oldIndex]; node.pithosContainer = pithosContainer; node.pithosObject = object; } } [newChildren addObject:node]; } } } // Else cache was used and all results were fetched during this request, so existing children can be reused [containerRequest release]; containerRequest = nil; [objects release]; objects = nil; // XXX sort children based on preferences @synchronized(self) { freshness = PithosNodeStateRefreshFinished; } // Notify observers that children are updated [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self]; } else { [containerRequest release]; // Do an additional request to fetch more objects containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name limit:0 marker:[[someObjects lastObject] name] prefix:prefix delimiter:@"/" path:nil meta:nil shared:NO until:nil] retain]; containerRequest.delegate = self; containerRequest.downloadCache = [ASIDownloadCache sharedCache]; [containerRequest startAsynchronous]; } } - (void)requestFailed:(ASIHTTPRequest *)request { // XXX do something on error, cleanup NSLog(@"error:%@", [containerRequest error]); [newChildren release]; newChildren = nil; [containerRequest release]; containerRequest = nil; [objects release]; objects = nil; @synchronized(self) { freshness = PithosNodeStateRefreshNeeded; } } #pragma mark - #pragma mark Properties - (NSString *)url { if (url == nil) url = [[NSString alloc] initWithFormat:@"%@/%@", [ASIPithosRequest storageURL], pithosContainer.name]; return url; } - (NSArray *)children { @synchronized(self) { switch (freshness) { case PithosNodeStateFresh: break; case PithosNodeStateRefreshNeeded: freshness = PithosNodeStateRefreshing; containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name limit:0 marker:nil prefix:prefix delimiter:@"/" path:nil meta:nil shared:NO until:nil] retain]; containerRequest.delegate = self; containerRequest.downloadCache = [ASIDownloadCache sharedCache]; [containerRequest startAsynchronous]; break; case PithosNodeStateRefreshing: break; case PithosNodeStateRefreshFinished: if (newChildren) { [children release]; children = newChildren; newChildren = nil; } freshness = PithosNodeStateFresh; default: break; } return children; } } - (NSString *)displayName { return [[pithosContainer.name copy] autorelease]; } - (NSImage *)icon { if (icon) return icon; return sharedIcon; } @end