// // PithosSubdirNode.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 "PithosSubdirNode.h" #import "ASIPithosRequest.h" #import "ASIPithosObjectRequest.h" #import "ASIPithosContainer.h" #import "ASIPithosObject.h" #import "ASIDownloadCache.h" #import "PithosUtilities.h" #import "PithosObjectNodeInfoController.h" static NSImage *sharedIcon = nil; @implementation PithosSubdirNode @synthesize pithosObject; @synthesize isPublic; + (void)initialize { if (self == [PithosSubdirNode class]) sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)] retain]; } #pragma mark - #pragma mark Object Lifecycle - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer pithosObject:(ASIPithosObject *)aPithosObject { if ((self = [super init])) { self.pithosContainer = aPithosContainer; self.pithosObject = aPithosObject; childrenUpdatedNotificationName = @"PithosSubdirNodeChildrenUpdated"; refreshParent = NO; } return self; } - (void)dealloc { [refreshMetadataObjectRequest clearDelegatesAndCancel]; [refreshMetadataObjectRequest release]; [applyMetadataObjectRequest clearDelegatesAndCancel]; [applyMetadataObjectRequest release]; [pithosObject release]; [super dealloc]; } #pragma mark - #pragma mark Properties - (NSString *)url { if (url == nil) url = [[NSString alloc] initWithFormat:@"subdir %@/%@/%@%@", (sharingAccount ? [ASIPithosRequest storageURLWithAuthUser:sharingAccount] : [ASIPithosRequest storageURL]), pithosContainer.name, prefix, (shared ? @"?shared" : @"")]; return url; } - (NSString *)displayName { if (displayName == nil) { displayName = [pithosObject.name lastPathComponent]; if (!pithosObject.subdir && [pithosObject.name hasSuffix:@"/"]) displayName = [displayName stringByAppendingString:@"/"]; [displayName retain]; } return [[displayName copy] autorelease]; } - (void)setDisplayName:(NSString *)aDisplayName { } - (NSImage *)icon { if (icon == nil) icon = [sharedIcon retain]; return icon; } - (void)setPithosObject:(ASIPithosObject *)aPithosObject { if (![pithosObject isEqualTo:aPithosObject]) { [pithosObject release]; pithosObject = [aPithosObject retain]; } if (pithosObject.subdir) { self.prefix = [pithosObject.name substringToIndex:([pithosObject.name length] - 1)]; } else { self.prefix = [NSString stringWithString:pithosObject.name]; } self.isPublic = (pithosObject.publicURI != nil); // Refresh browser if the object is in my shared and is no longer shared if (shared && !pithosObject.subdir && !pithosObject.sharing) { [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosBrowserRefreshNeeeded" object:self]; } } #pragma mark - #pragma mark ASIHTTPRequestDelegate - (void)objectRequestFinished:(ASIPithosObjectRequest *)request { NSLog(@"URL: %@", [request url]); NSLog(@"cached: %d", [request didUseCachedResponse]); if ([request isEqualTo:applyMetadataObjectRequest]) { int responseStatusCode = applyMetadataObjectRequest.responseStatusCode; if ((responseStatusCode != 201) && (responseStatusCode != 202)) [PithosUtilities unexpectedResponseStatusAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; } if ((responseStatusCode == 201) || (responseStatusCode == 202)) [self refreshInfo]; } else if ([request isEqualTo:refreshMetadataObjectRequest]) { [[pithosNodeInfoController window] makeFirstResponder:nil]; self.pithosObject = [refreshMetadataObjectRequest object]; if (refreshParent) { // Ask the parent for refresh for the case where an object was removed // It is done here so that it doesn't affect the info window refresh [parent refresh]; refreshParent = NO; } @synchronized(self) { [refreshMetadataObjectRequest release]; refreshMetadataObjectRequest = nil; } } } - (void)objectRequestFailed:(ASIPithosObjectRequest *)request { if ([request isEqualTo:applyMetadataObjectRequest]) { [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataObjectRequest]; @synchronized(self) { [applyMetadataObjectRequest release]; applyMetadataObjectRequest = nil; } } else if ([request isEqualTo:refreshMetadataObjectRequest]) { [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataObjectRequest]; @synchronized(self) { [refreshMetadataObjectRequest release]; refreshMetadataObjectRequest = nil; } } } #pragma mark - #pragma mark Info - (void)applyInfo { @synchronized(self) { if (applyMetadataObjectRequest == nil) { if (pithosObject.subdir) { BOOL createObject = NO; NSAlert *alert; ASIPithosObjectRequest *request = [ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name objectName:prefix]; [[PithosUtilities prepareRequest:request] startAsynchronous]; while (![request isFinished]) { usleep(1); } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"HTTP Request Error"]; [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; return; } else if (request.responseStatusCode == 200) { alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"Apply changes"]; [alert setInformativeText:[NSString stringWithFormat:@"In order to apply the changes in '%@', the object at the same path must be replaced. Continue?", self.displayName]]; [alert addButtonWithTitle:@"OK"]; [alert addButtonWithTitle:@"Cancel"]; NSInteger choice = [alert runModal]; if (choice == NSAlertFirstButtonReturn) { request = [ASIPithosObjectRequest deleteObjectRequestWithContainerName:pithosContainer.name objectName:prefix]; [[PithosUtilities prepareRequest:request] startAsynchronous]; while (![request isFinished]) { usleep(1); } if ([request error]) { alert = [[[NSAlert alloc] init] autorelease]; [alert setMessageText:@"HTTP Request Error"]; [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]]; [alert addButtonWithTitle:@"OK"]; [alert runModal]; return; } else if (request.responseStatusCode != 204) { [PithosUtilities unexpectedResponseStatusAlertWithRequest:request]; return; } refreshParent = YES; createObject = YES; } else { return; } } else if (request.responseStatusCode == 404) { createObject = YES; } else { [PithosUtilities unexpectedResponseStatusAlertWithRequest:request]; return; } if (createObject) { [[pithosNodeInfoController window] makeFirstResponder:nil]; applyMetadataObjectRequest = [[ASIPithosObjectRequest writeObjectDataRequestWithContainerName:pithosContainer.name objectName:prefix eTag:nil contentType:@"application/directory" contentEncoding:pithosObject.contentEncoding contentDisposition:pithosObject.contentDisposition manifest:pithosObject.manifest sharing:pithosObject.sharing isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) metadata:pithosObject.metadata data:[NSData data]] retain]; pithosObject.subdir = NO; applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } else { [[pithosNodeInfoController window] makeFirstResponder:nil]; if (sharingAccount) { applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithContainerName:pithosContainer.name objectName:pithosObject.name contentEncoding:nil contentDisposition:nil manifest:nil sharing:nil isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) metadata:pithosObject.metadata update:NO] retain]; [applyMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount]; } else { applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithContainerName:pithosContainer.name objectName:pithosObject.name contentEncoding:pithosObject.contentEncoding contentDisposition:pithosObject.contentDisposition manifest:pithosObject.manifest sharing:(pithosObject.sharing ? pithosObject.sharing : @"") isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse) metadata:pithosObject.metadata update:NO] retain]; } applyMetadataObjectRequest.delegate = self; applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); [[PithosUtilities prepareRequest:applyMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } } - (void)refreshInfo { @synchronized(self) { if (pithosObject.subdir) { self.pithosObject = [ASIPithosObject subdirWithName:pithosObject.name]; } else if (refreshMetadataObjectRequest == nil) { refreshMetadataObjectRequest = [[ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name objectName:prefix] retain]; if (sharingAccount) [refreshMetadataObjectRequest setRequestUserFromDefaultTo:sharingAccount]; refreshMetadataObjectRequest.delegate = self; refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:); refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:); refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache]; [[PithosUtilities prepareRequest:refreshMetadataObjectRequest priority:NSOperationQueuePriorityHigh] startAsynchronous]; } } } #pragma mark - #pragma mark Actions - (void)showPithosNodeInfo:(id)sender { if (!pithosNodeInfoController) pithosNodeInfoController = [[PithosObjectNodeInfoController alloc] initWithPithosNode:self]; [pithosNodeInfoController showWindow:sender]; [[pithosNodeInfoController window] makeKeyAndOrderFront:sender]; [NSApp activateIgnoringOtherApps:YES]; } @end