PageRenderTime 50ms CodeModel.GetById 17ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/update-engine/Core/KSUpdateCheckAction.m

http://macfuse.googlecode.com/
Objective C | 199 lines | 143 code | 31 blank | 25 comment | 17 complexity | 5869de022b1426a1406456a2dda96fc7 MD5 | raw file
  1// Copyright 2008 Google Inc.
  2//
  3// Licensed under the Apache License, Version 2.0 (the "License");
  4// you may not use this file except in compliance with the License.
  5// You may obtain a copy of the License at
  6//
  7//     http://www.apache.org/licenses/LICENSE-2.0
  8//
  9// Unless required by applicable law or agreed to in writing, software
 10// distributed under the License is distributed on an "AS IS" BASIS,
 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12// See the License for the specific language governing permissions and
 13// limitations under the License.
 14
 15#import "KSUpdateCheckAction.h"
 16
 17#import "GDataHTTPFetcher.h"
 18#import "KSActionConstants.h"
 19#import "KSActionPipe.h"
 20#import "KSActionProcessor.h"
 21#import "KSFetcherFactory.h"
 22#import "KSServer.h"
 23#import "KSTicket.h"
 24#import "KSUpdateAction.h"
 25
 26
 27@interface KSUpdateCheckAction (FetcherCallbacks)
 28
 29// A KSUpdateCheckAction may ask for information via GDataHTTPFetcher
 30// which is async.  These are callbacks passed to [GDataHTTPFetcher
 31// beginFetchingWithDelegate::::] to let us know what happened.
 32- (void)fetcher:(GDataHTTPFetcher *)fetcher finishedWithData:(NSData *)data;
 33- (void)fetcher:(GDataHTTPFetcher *)fetcher failedWithError:(NSError *)error;
 34
 35@end
 36
 37
 38@implementation KSUpdateCheckAction
 39
 40+ (id)checkerWithServer:(KSServer *)server tickets:(NSArray *)tickets {
 41  return [[[KSUpdateCheckAction alloc] initWithServer:server
 42                                              tickets:tickets] autorelease];
 43}
 44
 45- (id)init {
 46  return [self initWithServer:nil tickets:nil];
 47}
 48
 49- (id)initWithServer:(KSServer *)server tickets:(NSArray *)tickets {
 50  return [self initWithFetcherFactory:[KSFetcherFactory factory]
 51                               server:server
 52                              tickets:tickets];
 53}
 54
 55- (id)initWithFetcherFactory:(KSFetcherFactory *)fetcherFactory
 56                      server:(KSServer *)server
 57                     tickets:(NSArray *)tickets {
 58  if ((self = [super init])) {
 59    if ((fetcherFactory == nil) ||
 60        (server == nil) ||
 61        ([tickets count] == 0)) {
 62      [self release];
 63      return nil;
 64    }
 65    // check invariant; make sure all tickets point to the same server URL
 66    if ([tickets count] > 1) {
 67      KSTicket *first = [tickets objectAtIndex:0];
 68      NSEnumerator *tenum = [tickets objectEnumerator];
 69      KSTicket *t = nil;
 70      while ((t = [tenum nextObject])) {
 71        if (![[first serverURL] isEqual:[t serverURL]]) {
 72          GTMLoggerInfo(@"UpdateChecker passed tickets with different URLs?");
 73          [self release];
 74          return nil;
 75        }
 76      }
 77    }
 78    fetcherFactory_ = [fetcherFactory retain];
 79    server_ = [server retain];
 80    tickets_ = [tickets copy];
 81    fetchers_ = [[NSMutableArray alloc] init];
 82    allSuccessful_ = YES;  // so far...
 83  }
 84  return self;
 85}
 86
 87- (void)dealloc {
 88  [fetcherFactory_ release];
 89  [server_ release];
 90  [tickets_ release];
 91  [fetchers_ release];
 92  [super dealloc];
 93}
 94
 95// Override of -[KSAction performAction] to define ourselves as an
 96// action object.  Like KSAction, we are called from our owning
 97// KSActionProcessor.  This method happens to be async.
 98- (void)performAction {
 99  NSArray *requests = [server_ requestsForTickets:tickets_];
100
101  // Try and make debugging easier
102  NSEnumerator *renum = [requests objectEnumerator];
103  NSURLRequest *req = nil;
104
105#ifdef DEBUG
106  int x = 0;
107  while ((req = [renum nextObject])) {
108    NSData *data = [req HTTPBody];
109    // %.*s since we need length (data not NULL-terminated)
110    GTMLoggerDebug(@"** XML request %d:\n%.*s", x++,
111                  [data length], (char*)[data bytes]);
112  }
113#endif
114
115  renum = [requests objectEnumerator];
116  while ((req = [renum nextObject])) {
117    GDataHTTPFetcher *fetcher = [fetcherFactory_ createFetcherForRequest:req];
118    _GTMDevAssert(fetcher, @"no fetcher");
119    [fetchers_ addObject:fetcher];
120    [fetcher beginFetchWithDelegate:self
121                  didFinishSelector:@selector(fetcher:finishedWithData:)
122                    didFailSelector:@selector(fetcher:failedWithError:)];
123  }
124}
125
126- (void)terminateAction {
127  NSEnumerator *fenum = [fetchers_ objectEnumerator];
128  GDataHTTPFetcher *fetcher = nil;
129  while ((fetcher = [fenum nextObject])) {
130    if ([fetcher isFetching]) {
131      [fetcher stopFetching];
132    }
133  }
134  [fetchers_ removeAllObjects];
135}
136
137- (void)requestFinishedForFetcher:(GDataHTTPFetcher *)fetcher success:(BOOL)successful {
138  [fetchers_ removeObject:fetcher];
139  if (successful == NO)
140    allSuccessful_ = NO;
141  if ([fetchers_ count] == 0) {
142    [[self processor] finishedProcessing:self successfully:allSuccessful_];
143  }
144}
145
146- (int)outstandingRequests {
147  return [fetchers_ count];
148}
149
150- (id)delegate {
151  return delegate_;
152}
153
154- (void)setDelegate:(id)delegate {
155  delegate_ = delegate;
156}
157
158- (NSString *)description {
159  return [NSString stringWithFormat:@"<%@:%p server=%@ tickets=%@>",
160          [self class], self, server_, tickets_];
161}
162
163@end  // KSUpdateCheckAction
164
165
166@implementation KSUpdateCheckAction (FetcherCallbacks)
167
168- (void)fetcher:(GDataHTTPFetcher *)fetcher finishedWithData:(NSData *)data {
169  NSURLResponse *response = [fetcher response];
170  NSString *prettyData = [server_ prettyPrintResponse:response data:data];
171  GTMLoggerDebug(@"** XML response:\n%@", prettyData);
172
173  NSDictionary *oob;
174  NSArray *updateInfos = [server_ updateInfosForResponse:response
175                                                    data:data
176                                           outOfBandData:&oob];
177  KSTicket *first = [tickets_ objectAtIndex:0];
178  // If |oob| is nil for this dictionary creation, life is still good.
179  // The outgoing dictionary just won't have an out-of-band data
180  // element.
181  NSDictionary *results =
182    [NSDictionary dictionaryWithObjectsAndKeys:
183                  [first serverURL], KSActionServerURLKey,
184                  updateInfos, KSActionUpdateInfosKey,
185                  oob, KSActionOutOfBandDataKey,
186                  nil];
187  [[self outPipe] setContents:results];
188
189  [self requestFinishedForFetcher:fetcher success:YES];
190}
191
192- (void)fetcher:(GDataHTTPFetcher *)fetcher failedWithError:(NSError *)error {
193  GTMLoggerError(@"KSUpdateCheckAction failed with error %@", error);
194  if ([[self delegate] respondsToSelector:@selector(fetcher:failedWithError:)])
195    [[self delegate] fetcher:fetcher failedWithError:error];
196  [self requestFinishedForFetcher:fetcher success:NO];
197}
198
199@end