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 "PithosSubdirNode.h"
39 #import "ASIPithosRequest.h"
40 #import "ASIPithosObjectRequest.h"
41 #import "ASIPithosContainer.h"
42 #import "ASIPithosObject.h"
43 #import "ASIDownloadCache.h"
45 static NSImage *sharedIcon = nil;
47 @implementation PithosSubdirNode
48 @synthesize pithosObject;
52 if (self == [PithosSubdirNode class])
53 sharedIcon = [[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGenericFolderIcon)] retain];
57 #pragma mark Object Lifecycle
59 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer pithosObject:(ASIPithosObject *)aPithosObject {
60 if ((self = [super init])) {
61 self.pithosContainer = aPithosContainer;
62 self.pithosObject = aPithosObject;
63 childrenUpdatedNotificationName = @"PithosSubdirNodeChildrenUpdated";
70 [refreshMetadataObjectRequest clearDelegatesAndCancel];
71 [refreshMetadataObjectRequest release];
72 [applyMetadataObjectRequest clearDelegatesAndCancel];
73 [applyMetadataObjectRequest release];
74 [pithosObject release];
79 #pragma mark Properties
83 url = [[NSString alloc] initWithFormat:@"subdir %@/%@/%@", [ASIPithosRequest storageURL], pithosContainer.name, prefix];
87 - (NSString *)displayName {
88 // XXX check if there are problems with . or other special characters
89 return [pithosObject.name lastPathComponent];
98 - (void)setPithosObject:(ASIPithosObject *)aPithosObject {
99 if (![pithosObject isEqualTo:aPithosObject]) {
100 [pithosObject release];
101 pithosObject = [aPithosObject retain];
103 if (pithosObject.subdir) {
104 self.prefix = [pithosObject.name substringToIndex:([pithosObject.name length] - 1)];
106 self.prefix = [NSString stringWithString:pithosObject.name];
108 self.isPublic = (pithosObject.publicURI != nil);
115 @synchronized(self) {
116 if (applyMetadataObjectRequest == nil) {
117 if (pithosObject.subdir) {
118 BOOL createObject = NO;
120 ASIPithosObjectRequest *request = [ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name
122 [request startSynchronous];
123 if ([request error]) {
124 alert = [[[NSAlert alloc] init] autorelease];
125 [alert setMessageText:@"HTTP Request Error"];
126 [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]];
127 [alert addButtonWithTitle:@"OK"];
130 } else if (request.responseStatusCode == 200) {
131 alert = [[[NSAlert alloc] init] autorelease];
132 [alert setMessageText:@"Apply changes"];
133 [alert setInformativeText:[NSString stringWithFormat:@"In order to apply the changes in '%@', the object at the same path must be replaced. Continue?", self.displayName]];
134 [alert addButtonWithTitle:@"OK"];
135 [alert addButtonWithTitle:@"Cancel"];
136 NSInteger choice = [alert runModal];
137 if (choice == NSAlertFirstButtonReturn) {
138 request = [ASIPithosObjectRequest deleteContainerRequestWithContainerName:pithosContainer.name
140 [request startSynchronous];
141 if ([request error]) {
142 alert = [[[NSAlert alloc] init] autorelease];
143 [alert setMessageText:@"HTTP Request Error"];
144 [alert setInformativeText:[NSString stringWithFormat:@"An error occured: %@", [request error]]];
145 [alert addButtonWithTitle:@"OK"];
148 } else if (request.responseStatusCode != 204) {
149 alert = [[[NSAlert alloc] init] autorelease];
150 [alert setMessageText:@"Unexpected Response Status"];
151 [alert setInformativeText:[NSString stringWithFormat:@"Unexpected response status %d - %@", request.responseStatusCode, request.responseStatusMessage]];
152 [alert addButtonWithTitle:@"OK"];
161 } else if (request.responseStatusCode == 404) {
164 alert = [[[NSAlert alloc] init] autorelease];
165 [alert setMessageText:@"Unexpected Response Status"];
166 [alert setInformativeText:[NSString stringWithFormat:@"Unexpected response status %d - %@", request.responseStatusCode, request.responseStatusMessage]];
167 [alert addButtonWithTitle:@"OK"];
172 applyMetadataObjectRequest = [[ASIPithosObjectRequest writeObjectDataRequestWithContainerName:pithosContainer.name
175 contentType:@"application/directory"
177 contentDisposition:nil
179 sharing:pithosObject.sharing
180 isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse)
181 metadata:pithosObject.metadata
182 data:[NSData data]] retain];
183 pithosObject.subdir = NO;
184 applyMetadataObjectRequest.delegate = self;
185 applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
186 applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
187 [applyMetadataObjectRequest startAsynchronous];
190 applyMetadataObjectRequest = [[ASIPithosObjectRequest updateObjectMetadataRequestWithContainerName:pithosContainer.name
191 objectName:pithosObject.name
193 contentDisposition:nil
195 sharing:pithosObject.sharing
196 isPublic:(isPublic ? ASIPithosObjectRequestPublicTrue : ASIPithosObjectRequestPublicFalse)
197 metadata:pithosObject.metadata
199 applyMetadataObjectRequest.delegate = self;
200 applyMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
201 applyMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
202 [applyMetadataObjectRequest startAsynchronous];
208 - (void)refreshInfo {
209 @synchronized(self) {
210 if (pithosObject.subdir) {
211 self.pithosObject = [ASIPithosObject subdirWithName:pithosObject.name];
212 } else if (refreshMetadataObjectRequest == nil) {
213 refreshMetadataObjectRequest = [[ASIPithosObjectRequest objectMetadataRequestWithContainerName:pithosContainer.name
214 objectName:prefix] retain];
215 refreshMetadataObjectRequest.delegate = self;
216 refreshMetadataObjectRequest.didFinishSelector = @selector(objectRequestFinished:);
217 refreshMetadataObjectRequest.didFailSelector = @selector(objectRequestFailed:);
218 refreshMetadataObjectRequest.downloadCache = [ASIDownloadCache sharedCache];
219 [refreshMetadataObjectRequest startAsynchronous];
225 #pragma mark ASIHTTPRequestDelegate
227 - (void)objectRequestFinished:(ASIPithosObjectRequest *)request {
228 NSLog(@"URL: %@", [request url]);
229 NSLog(@"cached: %d", [request didUseCachedResponse]);
231 if ([request isEqualTo:applyMetadataObjectRequest]) {
232 @synchronized(self) {
233 [applyMetadataObjectRequest release];
234 applyMetadataObjectRequest = nil;
237 } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
238 self.pithosObject = [refreshMetadataObjectRequest object];
240 // Ask the parent for refresh for the case where an object was removed
241 // It is done here so that it doesn'e affect the info window refresh
242 [parent invalidateChildren];
246 @synchronized(self) {
247 [refreshMetadataObjectRequest release];
248 refreshMetadataObjectRequest = nil;
253 - (void)objectRequestFailed:(ASIPithosObjectRequest *)request {
254 if ([request isEqualTo:applyMetadataObjectRequest]) {
255 // XXX do something on error, cleanup
256 NSLog(@"error:%@", [applyMetadataObjectRequest error]);
257 @synchronized(self) {
258 [applyMetadataObjectRequest release];
259 applyMetadataObjectRequest = nil;
261 } else if ([request isEqualTo:refreshMetadataObjectRequest]) {
262 // XXX do something on error, cleanup
263 NSLog(@"error:%@", [refreshMetadataObjectRequest error]);
264 @synchronized(self) {
265 [refreshMetadataObjectRequest release];
266 refreshMetadataObjectRequest = nil;