PageRenderTime 33ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://macfuse.googlecode.com/
Objective C | 197 lines | 127 code | 35 blank | 35 comment | 16 complexity | dd9ae674f5fa0e4b6930636cc3ef692a MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  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. #import "KSCheckAction.h"
  15. #import "KSActionConstants.h"
  16. #import "KSActionPipe.h"
  17. #import "KSActionProcessor.h"
  18. #import "KSFrameworkStats.h"
  19. #import "KSPlistServer.h"
  20. #import "KSTicket.h"
  21. #import "KSTicketStore.h"
  22. #import "KSUpdateCheckAction.h"
  23. // The KSServer class used by this action is configurable. This variable holds
  24. // the objc Class representing the KSServer subclass to use. This variable
  25. // should not be directly accessed. Instead, the +serverClass class method
  26. // should be used. That class method will return a default KSServer class if one
  27. // is not set.
  28. static Class gServerClass; // Weak
  29. @implementation KSCheckAction
  30. + (id)actionWithTickets:(NSArray *)tickets params:(NSDictionary *)params
  31. engine:(KSUpdateEngine *)engine {
  32. return [[[self alloc] initWithTickets:tickets params:params engine:engine]
  33. autorelease];
  34. }
  35. + (id)actionWithTickets:(NSArray *)tickets params:(NSDictionary *)params {
  36. return [[[self alloc] initWithTickets:tickets params:params] autorelease];
  37. }
  38. + (id)actionWithTickets:(NSArray *)tickets {
  39. return [[[self alloc] initWithTickets:tickets] autorelease];
  40. }
  41. - (id)initWithTickets:(NSArray *)tickets params:(NSDictionary *)params
  42. engine:(KSUpdateEngine *)engine {
  43. if ((self = [super init])) {
  44. tickets_ = [tickets copy];
  45. params_ = [params retain];
  46. engine_ = [engine retain];
  47. updateInfos_ = [[NSMutableArray alloc] init];
  48. outOfBandData_ = [[NSMutableDictionary alloc] init];
  49. }
  50. return self;
  51. }
  52. - (id)initWithTickets:(NSArray *)tickets params:(NSDictionary *)params {
  53. return [self initWithTickets:tickets params:params engine:nil];
  54. }
  55. - (id)initWithTickets:(NSArray *)tickets {
  56. return [self initWithTickets:tickets params:nil];
  57. }
  58. - (void)dealloc {
  59. [tickets_ release];
  60. [updateInfos_ release];
  61. [outOfBandData_ release];
  62. [params_ release];
  63. [engine_ release];
  64. [super dealloc];
  65. }
  66. - (void)performAction {
  67. NSDictionary *tixMap = [tickets_ ticketsByURL];
  68. if (tixMap == nil) {
  69. GTMLoggerInfo(@"no tickets to check on.");
  70. [[self outPipe] setContents:nil];
  71. [[self processor] finishedProcessing:self successfully:YES];
  72. return;
  73. }
  74. NSURL *url = nil;
  75. NSEnumerator *tixMapEnumerator = [tixMap keyEnumerator];
  76. while ((url = [tixMapEnumerator nextObject])) {
  77. NSArray *tickets = [tixMap objectForKey:url];
  78. [[KSFrameworkStats sharedStats] incrementStat:kStatTickets
  79. by:[tickets count]];
  80. // We don't want to check for products that are currently not installed, so
  81. // we need to filter the array of tickets to only those ticktes whose
  82. // existence checker indicates that they are currently installed.
  83. // NSPredicate makes this very easy.
  84. NSArray *filteredTickets =
  85. [tickets filteredArrayUsingPredicate:
  86. [NSPredicate predicateWithFormat:@"existenceChecker.exists == YES"]];
  87. if ([filteredTickets count] == 0)
  88. continue;
  89. GTMLoggerInfo(@"filteredTickets = %@", filteredTickets);
  90. [[KSFrameworkStats sharedStats] incrementStat:kStatValidTickets
  91. by:[filteredTickets count]];
  92. Class serverClass = [[self class] serverClass];
  93. // Creates a concrete KSServer instance using the designated initializer
  94. // declared on KSServer. Pass along |engine_| so the server can call
  95. // delegate methods, if it needs to.
  96. KSServer *server = [[[serverClass alloc] initWithURL:url
  97. params:params_
  98. engine:engine_] autorelease];
  99. KSAction *checker = [KSUpdateCheckAction checkerWithServer:server
  100. tickets:filteredTickets];
  101. [[self subProcessor] enqueueAction:checker];
  102. }
  103. if ([[[self subProcessor] actions] count] == 0) {
  104. GTMLoggerInfo(@"No checkers created.");
  105. [[self processor] finishedProcessing:self successfully:YES];
  106. return;
  107. }
  108. // Our output needs to be the aggregate of all our sub-action checkers' output
  109. // For now, we'll just set our output to a dictionary holding
  110. // |updateInfos_| and |outOfBandData_|. When subactions complete,
  111. // we'll add their output to these two structures.
  112. [updateInfos_ removeAllObjects];
  113. [outOfBandData_ removeAllObjects];
  114. NSMutableDictionary *outPipeContents =
  115. [NSDictionary dictionaryWithObjectsAndKeys:
  116. updateInfos_, KSActionUpdateInfosKey,
  117. outOfBandData_, KSActionOutOfBandDataKey,
  118. nil];
  119. [[self outPipe] setContents:outPipeContents];
  120. [[self subProcessor] startProcessing];
  121. }
  122. // KSActionProcessor callback method that will be called by our subProcessor
  123. - (void)processor:(KSActionProcessor *)processor
  124. finishedAction:(KSAction *)action
  125. successfully:(BOOL)wasOK {
  126. [[KSFrameworkStats sharedStats] incrementStat:kStatChecks];
  127. if (wasOK) {
  128. // Get the checker's output contents and append it to our own output.
  129. NSDictionary *checkerOutput = [[action outPipe] contents];
  130. NSDictionary *oobData =
  131. [checkerOutput objectForKey:KSActionOutOfBandDataKey];
  132. NSURL *url = [checkerOutput objectForKey:KSActionServerURLKey];
  133. if (oobData && url) {
  134. [outOfBandData_ setObject:oobData forKey:[url description]];
  135. }
  136. NSArray *infos = [checkerOutput objectForKey:KSActionUpdateInfosKey];
  137. if (infos) {
  138. [updateInfos_ addObjectsFromArray:infos];
  139. }
  140. // See header comments about why this gets set to YES here.
  141. wasSuccessful_ = YES;
  142. } else {
  143. [[KSFrameworkStats sharedStats] incrementStat:kStatFailedChecks];
  144. }
  145. }
  146. // Overridden from KSMultiAction. Called by our subProcessor when it finishes.
  147. // We tell our parent processor that we succeeded if *any* of our subactions
  148. // succeeded.
  149. - (void)processingDone:(KSActionProcessor *)processor {
  150. [[self processor] finishedProcessing:self successfully:wasSuccessful_];
  151. }
  152. @end
  153. @implementation KSCheckAction (Configuration)
  154. + (Class)serverClass {
  155. return gServerClass ? gServerClass : [KSPlistServer class];
  156. }
  157. + (void)setServerClass:(Class)serverClass {
  158. if (serverClass != Nil && ![serverClass isSubclassOfClass:[KSServer class]])
  159. return;
  160. gServerClass = serverClass;
  161. }
  162. @end