1 2/*! 3 @header FTTransactionManagerImpl 4 @abstract Module of FT 5 6 @availability OS X, GNUstep 7 @copyright 2004, 2005, 2006 Free Software Foundation, Inc. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 23 <pre> 24 ------------------------------------------------------------------------- 25 Modification history 26 27 26.06.05 ola initial version 28 23.08.06 ola license changed 29 ------------------------------------------------------------------------- 30 </pre> 31*/ 32 33#include <Encore/Encore.h> 34#include <FT/FTTransactionManager.h> 35#include <FT/FTSession.h> 36#include <FT/FTSessionImpl.h> 37#include <FT/FTTransactionManagerImpl.h> 38#include <FT/FTTransactionImpl.h> 39#include <FT/FTExceptions.h> 40#include <FT/FTLogging.h> 41 42 43@implementation FTTransactionManagerImpl 44 45- init { 46 self = [super init]; 47 48 self->globalLock = [[NSLock alloc] init]; 49 50 self->sessionIdToTransactionArray = [[NSMutableDictionary alloc] init]; 51 self->transactionOptimizers = [[NSMutableArray alloc] init]; 52 53 return self; 54} 55 56 57- (void) dealloc { 58 [self->globalLock release]; 59 [self->sessionIdToTransactionArray dealloc]; 60 [self->transactionOptimizers release]; 61 62 [super dealloc]; 63} 64 65 66- addTransactionOptimizer: (id <FTTransactionOptimizer>) optimizerToAdd 67 withPriority: (unsigned) priority { 68 69 if( 0 != priority ) { 70 [[[ECIllegalArgumentException alloc] 71 initWithArgumentInfo: @"FTTransactionManagerImpl::addTransactionOptimizer"\ 72 ": priority must equal 0 at present" ] raise]; 73 } 74 75 [self->transactionOptimizers addObject: optimizerToAdd]; 76 77 return self; 78} 79 80 81- (BOOL) commitTransaction: (id <FTTransaction>) transactionToCommit { 82 BOOL success = YES; 83 FTTransactionImpl *impl; 84 NSEnumerator *steps; 85 id currentStep; 86 FTTransactionUndoStack *performedActions; 87 NSException *stepException = nil; 88 89 if( [[FTLogging coreLog] isDebugEnabled] ) { 90 [[FTLogging coreLog] 91 debug: @"FTTransactionManagerImpl::commit: Starting commitment..." ]; 92 } 93 94 if( ![transactionToCommit isKindOfClass: [FTTransactionImpl class]] ) { 95 [[[ECIllegalArgumentException alloc] initWithArgumentInfo: 96 @"transactionToCommit is not derived from FTTransactionImpl"] raise]; 97 } 98 99 [self->globalLock lock]; 100 impl = (FTTransactionImpl *) [self optimizeTransaction: transactionToCommit]; 101 steps = [[impl transactionSteps] objectEnumerator]; 102 performedActions = [[FTTransactionUndoStack alloc] init]; 103 104 while( (currentStep = [steps nextObject]) && success ) { 105 if( [currentStep isKindOfClass: [FTTransactionStepAndContext class]] ) { 106 id <FTTransactionStep> step; 107 FTTransactionContext *context; 108 109 step = [((FTTransactionStepAndContext *) currentStep) transactionStep]; 110 context = [((FTTransactionStepAndContext *) currentStep) 111 transactionContext]; 112 113 if( nil != step ) { 114 NS_DURING 115 success = [step performAction: context]; 116 NS_HANDLER 117 success = NO; 118 stepException = [localException retain]; 119 break; 120 NS_ENDHANDLER 121 } 122 123 if( success ) { 124 [performedActions addPerformedStep: currentStep]; 125 } 126 } 127 } 128 129 if( NO == success ) { 130 // at least one step failed 131 /** 132 * TODO 133 * At present we simply call "undoAction" of all actions 134 * directly launched before. 135 * TODO: Much more robust behaviour here 136 */ 137 NS_DURING 138 [performedActions undoAll]; 139 NS_HANDLER 140 /** 141 * Evil situation if an exception occurs here 142 */ 143 [self->globalLock unlock]; 144 145 if( nil != stepException ) { 146 [stepException release]; 147 } 148 149 [performedActions release]; 150 151 [[[FTTransactionStepException alloc] 152 initWithTransactionStepException: localException] raise]; 153 NS_ENDHANDLER 154 155 if( nil != stepException ) { 156 [stepException raise]; 157 } 158 } 159 160 [self->globalLock unlock]; 161 [performedActions release]; 162 163 return success; 164} 165 166 167- (id <FTTransaction>) createTransactionForSession: (id <FTSession>) session { 168 FTTransactionImpl *transaction = [[[FTTransactionImpl alloc] 169 initForTransactionManager: self ] autorelease]; 170 171 [self->globalLock lock]; 172 ECStack *transactionStack 173 = [sessionIdToTransactionArray objectForKey: [session sessionId]]; 174 175 if( nil == transactionStack ) { 176 /** create stack: */ 177 transactionStack = [[ECStack alloc] init]; 178 [self->sessionIdToTransactionArray 179 setObject: transactionStack forKey: [session sessionId] ]; 180 } 181 182 NSAssert( nil != transactionStack, @"Ups, transaction stack equals nil!" ); 183 184 [transactionStack pushObject: transaction]; 185 186 [self->globalLock unlock]; 187 188 return transaction; 189} 190 191 192- (id <FTTransaction>) currentTransactionForSession: (id <FTSession>) session { 193 ECStack *transactionStack; 194 195 transactionStack = [self->sessionIdToTransactionArray objectForKey: 196 [session sessionId]]; 197 NSAssert( nil != transactionStack, @"Cannot find stack for storing "\ 198 "transactions!" ); 199 200 return [transactionStack topObject]; 201} 202 203 204- (id <FTTransaction>) optimizeTransaction: (id <FTTransaction>) transaction { 205 id <FTTransaction> toReturn = transaction; 206 NSEnumerator *enumerator; 207 id <FTTransactionOptimizer> transactionOptimizer; 208 209 enumerator = [self->transactionOptimizers objectEnumerator]; 210 211 while( nil != (transactionOptimizer 212 = (id <FTTransactionOptimizer>) [enumerator nextObject] )) { 213 toReturn = [transactionOptimizer optimizeTransaction: toReturn]; 214 } 215 216 return toReturn; 217} 218@end 219 220 221@implementation FTTransactionUndoStack 222 223- init { 224 self = [super init]; 225 226 self->undoSteps = [[ECStack alloc] init]; 227 self->performedUndoSteps = [[ECStack alloc] init]; 228 self->currentUndoStep = nil; 229 return self; 230} 231 232 233- (void) dealloc { 234 [self->undoSteps release]; 235 [self->performedUndoSteps release]; 236 if( nil != self->currentUndoStep ) { 237 [self->currentUndoStep release]; 238 } 239 240 [super dealloc]; 241} 242 243 244- addPerformedStep: (FTTransactionStepAndContext *) stepToAdd { 245 if( nil != stepToAdd ) { 246 [self->undoSteps pushObject: stepToAdd]; 247 } 248 249 return self; 250} 251 252 253- undoAll { 254 while( NO == [undoSteps isEmpty] ) { 255 self->currentUndoStep 256 = (FTTransactionStepAndContext *) [self->undoSteps popObject]; 257 258 if( nil != self->currentUndoStep ) { 259 [[self->currentUndoStep transactionStep] 260 undoAction: [self->currentUndoStep transactionContext]]; 261 262 [self->performedUndoSteps pushObject: self->currentUndoStep]; 263 [self->currentUndoStep release]; 264 self->currentUndoStep = nil; 265 } 266 } 267 268 return self; 269} 270 271@end 272