Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / PithosSubdirNode.m @ d4433f6f

History | View | Annotate | Download (21.7 kB)

1
//
2
//  PithosSubdirNode.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 "PithosSubdirNode.h"
39
#import "ASIPithosRequest.h"
40
#import "ASIPithos.h"
41
#import "ASIPithosObjectRequest.h"
42
#import "ASIPithosContainer.h"
43
#import "ASIPithosObject.h"
44
#import "ASINetworkQueue.h"
45
#import "ASIDownloadCache.h"
46
#import "PithosUtilities.h"
47
#import "PithosObjectNodeInfoController.h"
48

    
49
static NSImage *sharedIcon = nil;
50

    
51
@implementation PithosSubdirNode
52
@synthesize pithosObject;
53
@synthesize isPublic;
54

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

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

    
63
- (id)initWithPithos:(ASIPithos *)aPithos 
64
     pithosContainer:(ASIPithosContainer *)aPithosContainer 
65
        pithosObject:(ASIPithosObject *)aPithosObject {
66
    if ((self = [super init])) {
67
        self.pithos = aPithos;
68
        self.pithosContainer = aPithosContainer;
69
        self.pithosObject = aPithosObject;
70
        refreshParent = NO;
71
    }
72
    return self;
73
}
74

    
75
- (void)dealloc {
76
    [refreshMetadataObjectRequest clearDelegatesAndCancel];
77
    [refreshMetadataObjectRequest release];
78
    [applyMetadataObjectRequest clearDelegatesAndCancel];
79
    [applyMetadataObjectRequest release];
80
    [pithosObject release];
81
    [super dealloc];
82
}
83

    
84
#pragma mark -
85
#pragma mark Properties
86

    
87
- (void)setPithos:(ASIPithos *)aPithos {
88
    if (aPithos && ![aPithos isEqualTo:pithos]) {
89
        [pithos release];
90
        pithos = [aPithos retain];
91
        [url release];
92
        url = nil;
93
    }
94
}
95

    
96
- (NSString *)url {
97
    if (url == nil)
98
        url = [[NSString alloc] initWithFormat:@"subdir %@/%@/%@%@", 
99
               (sharingAccount ? [pithos storageURLWithAuthUser:sharingAccount] : pithos.storageURL), 
100
               pithosContainer.name, 
101
               prefix, 
102
               (shared ? @"?shared" : @"")];
103
    return url;
104
}
105

    
106
- (NSString *)displayName {
107
    if (displayName == nil) {
108
        displayName = [pithosObject.name lastPathComponent];
109
        if (!pithosObject.subdir && [pithosObject.name hasSuffix:@"/"])
110
            displayName = [displayName stringByAppendingString:@"/"];
111
        [displayName retain];
112
    } 
113
    return [[displayName copy] autorelease];
114
}
115

    
116
- (void)setDisplayName:(NSString *)aDisplayName {    
117
}
118

    
119
- (NSImage *)icon {
120
    if (icon == nil)
121
        icon = [sharedIcon retain];
122
    return icon;
123
}
124

    
125
- (void)setPithosObject:(ASIPithosObject *)aPithosObject {
126
    if (![pithosObject isEqualTo:aPithosObject]) {
127
        [pithosObject release];
128
        pithosObject = [aPithosObject retain];
129
    }
130
    if (pithosObject.subdir) {
131
        self.prefix = [pithosObject.name substringToIndex:([pithosObject.name length] - 1)];
132
    } else {
133
        self.prefix = [NSString stringWithString:pithosObject.name];
134
    }
135
    self.isPublic = (pithosObject.publicURI != nil);
136
    // Refresh browser if the object is in my shared and is no longer shared
137
    if (shared && !pithosObject.subdir && !pithosObject.sharing) {
138
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosBrowserRefreshNeeeded" object:self];
139
    }
140
}
141

    
142
- (void)setLimitedPithosObject:(ASIPithosObject *)aPithosObject {
143
    if (![pithosObject isEqualTo:aPithosObject]) {
144
        self.pithosObject.subdir = aPithosObject.subdir;
145
        self.pithosObject.name = aPithosObject.name;
146
        self.pithosObject.hash = aPithosObject.hash;
147
        self.pithosObject.objectHash = aPithosObject.objectHash;
148
        self.pithosObject.UUID = aPithosObject.UUID;
149
        self.pithosObject.bytes = aPithosObject.bytes;
150
        self.pithosObject.contentType = aPithosObject.contentType;
151
        self.pithosObject.lastModified = aPithosObject.lastModified;
152
        self.pithosObject.version = aPithosObject.version;
153
        self.pithosObject.versionTimestamp = aPithosObject.versionTimestamp;
154
        self.pithosObject.modifiedBy = aPithosObject.modifiedBy;
155
        self.pithosObject.sharedBy = aPithosObject.sharedBy;
156
        self.pithosObject.allowedTo = aPithosObject.allowedTo;
157
        if (!pithosNodeInfoController) {
158
            self.pithosObject.sharing = aPithosObject.sharing;
159
            self.pithosObject.publicURI = aPithosObject.publicURI;
160
            self.pithosObject = pithosObject;
161
        }
162
    }
163
}
164

    
165
#pragma mark -
166
#pragma mark ASIHTTPRequestDelegate
167

    
168
- (void)objectRequestFinished:(ASIPithosObjectRequest *)request {
169
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
170
    NSLog(@"URL: %@", [request url]);
171
    NSLog(@"cached: %d", [request didUseCachedResponse]);
172
    
173
    if ([request isEqualTo:applyMetadataObjectRequest]) {
174
        int responseStatusCode = applyMetadataObjectRequest.responseStatusCode;
175
        if ((responseStatusCode != 201) && (responseStatusCode != 202))
176
            [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest];
177
        @synchronized(self) {
178
            [applyMetadataObjectRequest release];
179
            applyMetadataObjectRequest = nil;
180
        }
181
        if ((responseStatusCode == 201) || (responseStatusCode == 202))
182
            [self refreshInfo];
183
    } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
184
        [[pithosNodeInfoController window] makeFirstResponder:nil];
185
        self.pithosObject = [refreshMetadataObjectRequest object];
186
        if (refreshParent) {
187
            // Ask the parent for refresh for the case where an object was removed
188
            // It is done here so that it doesn't affect the info window refresh
189
            [parent refresh];
190
            refreshParent = NO;
191
        }
192
        @synchronized(self) {
193
            [refreshMetadataObjectRequest release];
194
            refreshMetadataObjectRequest = nil;
195
        }
196
    }
197
    [pool drain];
198
}
199

    
200
- (void)objectRequestFailed:(ASIPithosObjectRequest *)request {
201
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
202
    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
203
    if (retries > 0) {
204
        ASIPithosObjectRequest *newRequest = (ASIPithosObjectRequest *)[[PithosUtilities copyRequest:request] autorelease];
205
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
206
        if ([request isEqualTo:applyMetadataObjectRequest]) {
207
            @synchronized(self) {
208
                [applyMetadataObjectRequest release];
209
                applyMetadataObjectRequest = newRequest;
210
            }
211
        } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
212
            @synchronized(self) {
213
                [refreshMetadataObjectRequest release];
214
                refreshMetadataObjectRequest = newRequest;
215
            }
216
        }
217
        [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
218
    } else {
219
        if ([request isEqualTo:applyMetadataObjectRequest]) {
220
            dispatch_async(dispatch_get_main_queue(), ^{
221
                [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest];
222
            });
223
            @synchronized(self) {
224
                [applyMetadataObjectRequest release];
225
                applyMetadataObjectRequest = nil;
226
            }
227
        } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
228
            dispatch_async(dispatch_get_main_queue(), ^{
229
                [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest];
230
            });
231
            @synchronized(self) {
232
                [refreshMetadataObjectRequest release];
233
                refreshMetadataObjectRequest = nil;
234
            }
235
        }
236
    }
237
    [pool drain];
238
}
239

    
240
#pragma mark -
241
#pragma mark Info
242

    
243
- (void)applyInfo {
244
    @synchronized(self) {
245
        if (applyMetadataObjectRequest == nil) {
246
            if (pithosObject.subdir) {
247
                BOOL createObject = NO;
248
                NSAlert *alert;
249
                ASIPithosObjectRequest *request = [ASIPithosObjectRequest objectMetadataRequestWithPithos:pithos 
250
                                                                                            containerName:pithosContainer.name 
251
                                                                                               objectName:prefix];
252
                ASINetworkQueue *networkQueue = [ASINetworkQueue queue];
253
                [networkQueue go];
254
                [networkQueue addOperations:[NSArray arrayWithObject:[PithosUtilities prepareRequest:request]] waitUntilFinished:YES];
255
                if ([request error]) {
256
                    alert = [[[NSAlert alloc] init] autorelease];
257
                    [alert setMessageText:@"HTTP Request Error"];
258
                    [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]];
259
                    [alert addButtonWithTitle:@"OK"];
260
                    [alert runModal];
261
                    return;
262
                } else if (request.responseStatusCode == 200) {
263
                    alert = [[[NSAlert alloc] init] autorelease];
264
                    [alert setMessageText:@"Apply changes"];
265
                    [alert setInformativeText:[NSString stringWithFormat:@"In order to apply the changes in '%@', the object at the same path must be replaced. Continue?", self.displayName]];
266
                    [alert addButtonWithTitle:@"OK"];
267
                    [alert addButtonWithTitle:@"Cancel"];
268
                    NSInteger choice = [alert runModal];
269
                    if (choice == NSAlertFirstButtonReturn) {
270
                        request = [ASIPithosObjectRequest deleteObjectRequestWithPithos:pithos 
271
                                                                          containerName:pithosContainer.name 
272
                                                                             objectName:prefix];
273
                        ASINetworkQueue *networkQueue = [ASINetworkQueue queue];
274
                        [networkQueue go];
275
                        [networkQueue addOperations:[NSArray arrayWithObject:[PithosUtilities prepareRequest:request]] waitUntilFinished:YES];
276
                        if ([request error]) {
277
                            alert = [[[NSAlert alloc] init] autorelease];
278
                            [alert setMessageText:@"HTTP Request Error"];
279
                            [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]];
280
                            [alert addButtonWithTitle:@"OK"];
281
                            [alert runModal];
282
                            return;
283
                        } else if (request.responseStatusCode != 204) {
284
                            [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
285
                            return;
286
                        }
287
                        refreshParent = YES;
288
                        createObject = YES;
289
                    } else {
290
                        return;
291
                    }
292
                } else if (request.responseStatusCode == 404) {
293
                    createObject = YES;
294
                } else {
295
                    [PithosUtilities unexpectedResponseStatusAlertWithRequest:request];
296
                    return;
297
                }
298
                if (createObject) {
299
                    [[pithosNodeInfoController window] makeFirstResponder:nil];
300
                    applyMetadataObjectRequest = [[ASIPithosObjectRequest writeObjectDataRequestWithPithos:pithos 
301
                                                                                             containerName:pithosContainer.name 
302
                                                                                                objectName:prefix 
303
                                                                                                      eTag:nil
304
                                                                                               contentType:@"application/directory"
305
                                                                                           contentEncoding:pithosObject.contentEncoding 
306
                                                                                        contentDisposition:pithosObject.contentDisposition 
307
                                                                                                  manifest:pithosObject.manifest 
308
                                                                                                   sharing:pithosObject.sharing 
309
                                                                                                  isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) 
310
                                                                                                  metadata:pithosObject.metadata 
311
                                                                                                      data:[NSData data]] retain];
312
                    pithosObject.subdir = NO;
313
                    applyMetadataObjectRequest.delegate = self;
314
                    applyMetadataObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
315
                    applyMetadataObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
316
                    applyMetadataObjectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
317
                                                           [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
318
                                                           [NSNumber numberWithUnsignedInteger:10], @"retries", 
319
                                                           NSStringFromSelector(@selector(objectRequestFinished:)), @"didFinishSelector", 
320
                                                           NSStringFromSelector(@selector(objectRequestFailed:)), @"didFailSelector", 
321
                                                           nil];
322
                    [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
323
                }
324
            } else {
325
                [[pithosNodeInfoController window] makeFirstResponder:nil];
326
                if (sharingAccount) {
327
                    applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithos 
328
                                                                                                  containerName:pithosContainer.name 
329
                                                                                                     objectName:pithosObject.name 
330
                                                                                                contentEncoding:nil
331
                                                                                             contentDisposition:nil
332
                                                                                                       manifest:nil 
333
                                                                                                        sharing:nil 
334
                                                                                                       isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) 
335
                                                                                                       metadata:pithosObject.metadata
336
                                                                                                         update:NO] retain];
337
                    [applyMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
338
                } else {
339
                    applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithPithos:pithos 
340
                                                                                                  containerName:pithosContainer.name 
341
                                                                                                     objectName:pithosObject.name 
342
                                                                                                contentEncoding:pithosObject.contentEncoding
343
                                                                                             contentDisposition:pithosObject.contentDisposition 
344
                                                                                                       manifest:pithosObject.manifest 
345
                                                                                                        sharing:(pithosObject.sharing ? pithosObject.sharing : @"") 
346
                                                                                                       isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) 
347
                                                                                                       metadata:pithosObject.metadata
348
                                                                                                         update:NO] retain];
349
                }
350
                applyMetadataObjectRequest.delegate = self;
351
                applyMetadataObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
352
                applyMetadataObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
353
                applyMetadataObjectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
354
                                                       [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
355
                                                       [NSNumber numberWithUnsignedInteger:10], @"retries", 
356
                                                       NSStringFromSelector(@selector(objectRequestFinished:)), @"didFinishSelector", 
357
                                                       NSStringFromSelector(@selector(objectRequestFailed:)), @"didFailSelector", 
358
                                                       nil];
359
                [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
360
            }
361
        }
362
    }
363
}
364

    
365
- (void)refreshInfo {
366
    @synchronized(self) {
367
        if (pithosObject.subdir) {
368
            self.pithosObject = [ASIPithosObject subdirWithName:pithosObject.name];
369
        } else if (refreshMetadataObjectRequest == nil) {
370
            refreshMetadataObjectRequest = [[ASIPithosObjectRequest objectMetadataRequestWithPithos:pithos 
371
                                                                                      containerName:pithosContainer.name 
372
                                                                                         objectName:prefix] retain];
373
            if (sharingAccount)
374
                [refreshMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount withPithos:pithos];
375
            refreshMetadataObjectRequest.delegate = self;
376
            refreshMetadataObjectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
377
            refreshMetadataObjectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
378
            refreshMetadataObjectRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
379
                                                     [NSNumber numberWithInteger:NSOperationQueuePriorityHigh], @"priority", 
380
                                                     [NSNumber numberWithUnsignedInteger:10], @"retries", 
381
                                                     NSStringFromSelector(@selector(objectRequestFinished:)), @"didFinishSelector", 
382
                                                     NSStringFromSelector(@selector(objectRequestFailed:)), @"didFailSelector", 
383
                                                     nil];
384
            refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache];
385
            [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous];
386
        }
387
    }
388
}
389

    
390
#pragma mark -
391
#pragma mark Actions
392

    
393
- (void)showPithosNodeInfo:(id)sender {
394
    if (!pithosNodeInfoController) {
395
        pithosNodeInfoController = [[PithosObjectNodeInfoController alloc] initWithPithosNode:self];
396
        [self refreshInfo];
397
    }
398
    [pithosNodeInfoController showWindow:sender];
399
    [[pithosNodeInfoController window] makeKeyAndOrderFront:sender];
400
    [NSApp activateIgnoringOtherApps:YES];
401
}
402

    
403
@end