2 // PithosContainerNode.m
5 // Copyright 2011 GRNET S.A. All rights reserved.
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
11 // 1. Redistributions of source code must retain the above
12 // copyright notice, this list of conditions and the following
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.
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.
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.
38 #import "PithosContainerNode.h"
39 #import "PithosObjectNode.h"
40 #import "PithosSubdirNode.h"
41 #import "ASIPithosContainerRequest.h"
42 #import "ASIPithosContainer.h"
43 #import "ASIPithosObject.h"
44 #import "ASIDownloadCache.h"
45 #import "PithosFileUtilities.h"
47 static NSImage *sharedIcon = nil;
49 @implementation PithosContainerNode
50 @synthesize pithosContainer, prefix;
53 if (self == [PithosContainerNode class])
54 sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericHardDiskIcon)] retain];
58 #pragma mark Object Lifecycle
60 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
61 if ((self = [super init])) {
62 self.pithosContainer = aPithosContainer;
64 icon = [anIcon retain];
65 childrenUpdatedNotificationName = @"PithosContainerNodeChildrenUpdated";
70 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer {
71 return [self initWithPithosContainer:aPithosContainer icon:nil];
74 - (id)initWithContainerName:(NSString *)aContainerName icon:(NSImage *)anIcon {
75 ASIPithosContainer *container = [ASIPithosContainer container];
76 container.name = aContainerName;
77 return [self initWithPithosContainer:container icon:anIcon];
80 - (id)initWithContainerName:(NSString *)aContainerName {
81 return [self initWithContainerName:aContainerName icon:nil];
85 [containerRequest clearDelegatesAndCancel];
86 [containerRequest release];
87 [childrenUpdatedNotificationName release];
90 [pithosContainer release];
95 #pragma mark ASIHTTPRequestDelegate
97 - (void)containerRequestFinished:(ASIPithosContainerRequest *)request {
98 NSLog(@"URL: %@", [containerRequest url]);
99 NSLog(@"cached: %d", [containerRequest didUseCachedResponse]);
101 if ((pithosContainer.blockHash == nil) || (pithosContainer.blockSize == 0)) {
102 pithosContainer.blockHash = [containerRequest blockHash];
103 pithosContainer.blockSize = [containerRequest blockSize];
106 NSArray *someObjects = [containerRequest objects];
107 if (objects == nil) {
108 objects = [[NSMutableArray alloc] initWithArray:someObjects];
110 [objects addObjectsFromArray:someObjects];
112 if ([someObjects count] < 10000) {
113 if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
115 NSLog(@"using newChildren");
116 newChildren = [[NSMutableArray alloc] init];
117 NSArray *objectNames = [objects valueForKey:@"name"];
118 NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
119 BOOL isSubdirNode = ([self class] == [PithosSubdirNode class]);
120 for (ASIPithosObject *object in objects) {
122 [object.name hasPrefix:[((PithosSubdirNode *)self).prefix stringByAppendingString:@"/"]]) {
123 // The check above removes false objects due to trailing slash or same prefix
125 NSUInteger sameNameObjectIndex = [objectNames indexOfObject:[object.name substringToIndex:([object.name length] - 1)]];
126 if ((sameNameObjectIndex == NSNotFound) ||
127 ![[[objects objectAtIndex:sameNameObjectIndex] contentType] isEqualToString:@"application/directory"]) {
128 PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
131 NSUInteger oldIndex = [children indexOfObject:node];
132 if (oldIndex != NSNotFound) {
133 // Use the same pointer value, if possible
134 node = [children objectAtIndex:oldIndex];
135 node.pithosContainer = pithosContainer;
136 node.pithosObject = object;
137 [keptNodes addIndex:oldIndex];
140 [newChildren addObject:node];
142 } else if ([object.contentType isEqualToString:@"application/directory"]) {
143 PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
146 NSUInteger oldIndex = [children indexOfObject:node];
147 if (oldIndex != NSNotFound) {
148 // Use the same pointer value, if possible
149 node = [children objectAtIndex:oldIndex];
150 node.pithosContainer = pithosContainer;
151 node.pithosObject = object;
152 [keptNodes addIndex:oldIndex];
155 [newChildren addObject:node];
157 PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
160 NSUInteger oldIndex = [children indexOfObject:node];
161 if (oldIndex != NSNotFound) {
162 // Use the same pointer value, if possible
163 node = [children objectAtIndex:oldIndex];
164 node.pithosContainer = pithosContainer;
165 node.pithosObject = object;
166 [keptNodes addIndex:oldIndex];
169 [newChildren addObject:node];
173 [[children objectsAtIndexes:
174 [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
175 if ([keptNodes containsIndex:idx])
178 }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
180 // Else cache was used and all results were fetched during this request, so existing children can be reused
181 [containerRequest release];
182 containerRequest = nil;
185 @synchronized(self) {
186 freshness = PithosNodeStateRefreshFinished;
188 // Notify observers that children are updated
189 [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
191 [containerRequest release];
192 // Do an additional request to fetch more objects
193 containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name
195 marker:[[someObjects lastObject] name]
202 containerRequest.delegate = self;
203 containerRequest.downloadCache = [ASIDownloadCache sharedCache];
204 [containerRequest startAsynchronous];
208 - (void)containerRequestFailed:(ASIPithosContainerRequest *)request {
209 [PithosFileUtilities httpRequestErrorAlertWithRequest:request];
210 [newChildren release];
212 [containerRequest release];
213 containerRequest = nil;
216 @synchronized(self) {
217 freshness = PithosNodeStateRefreshNeeded;
222 #pragma mark Properties
226 url = [[NSString alloc] initWithFormat:@"%@/%@", [ASIPithosRequest storageURL], pithosContainer.name];
230 - (NSArray *)children {
231 @synchronized(self) {
233 case PithosNodeStateFresh:
235 case PithosNodeStateRefreshNeeded:
236 freshness = PithosNodeStateRefreshing;
237 containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name
246 containerRequest.delegate = self;
247 containerRequest.didFinishSelector = @selector(containerRequestFinished:);
248 containerRequest.didFailSelector = @selector(containerRequestFailed:);
249 containerRequest.downloadCache = [ASIDownloadCache sharedCache];
250 [containerRequest startAsynchronous];
252 case PithosNodeStateRefreshing:
254 case PithosNodeStateRefreshFinished:
257 children = newChildren;
260 freshness = PithosNodeStateFresh;
268 - (NSString *)displayName {
269 return [[pithosContainer.name copy] autorelease];
278 - (void)setIcon:(NSImage *)anIcon {
280 icon = [anIcon retain];