1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_framework.hxx" 26 27 //_________________________________________________________________________________________________________________ 28 // my own includes 29 //_________________________________________________________________________________________________________________ 30 #include <threadhelp/transactionmanager.hxx> 31 #include <threadhelp/resetableguard.hxx> 32 #include <macros/debug.hxx> 33 34 #include <macros/generic.hxx> 35 #include <fwidllapi.h> 36 37 //_________________________________________________________________________________________________________________ 38 // interface includes 39 //_________________________________________________________________________________________________________________ 40 #include <com/sun/star/lang/DisposedException.hpp> 41 //_________________________________________________________________________________________________________________ 42 // other includes 43 //_________________________________________________________________________________________________________________ 44 45 //_________________________________________________________________________________________________________________ 46 // const 47 //_________________________________________________________________________________________________________________ 48 49 //_________________________________________________________________________________________________________________ 50 // namespace 51 //_________________________________________________________________________________________________________________ 52 53 namespace framework{ 54 55 //_________________________________________________________________________________________________________________ 56 // non exported const 57 //_________________________________________________________________________________________________________________ 58 59 //_________________________________________________________________________________________________________________ 60 // non exported declarations 61 //_________________________________________________________________________________________________________________ 62 63 //_________________________________________________________________________________________________________________ 64 // definitions 65 //_________________________________________________________________________________________________________________ 66 67 /*-************************************************************************************************************//** 68 @short standard ctor 69 @descr Initialize instance with right start values for correct working. 70 71 @seealso - 72 73 @param - 74 @return - 75 76 @onerror - 77 *//*-*************************************************************************************************************/ 78 TransactionManager::TransactionManager() 79 : m_eWorkingMode ( E_INIT ) 80 , m_nTransactionCount ( 0 ) 81 { 82 m_aBarrier.open(); 83 } 84 85 /*-************************************************************************************************************//** 86 @short standard dtor 87 @descr - 88 89 @seealso - 90 91 @param - 92 @return - 93 94 @onerror - 95 *//*-*************************************************************************************************************/ 96 TransactionManager::~TransactionManager() 97 { 98 } 99 100 /*-****************************************************************************************************//** 101 @interface ITransactionManager 102 @short set new working mode 103 @descr These implementation knows for states of working: E_INIT, E_WORK, E_CLOSING, E_CLOSE 104 You can step during this ones only from the left to the right side and start at left side again! 105 (This is necessary e.g. for refcounted objects!) 106 This call will block till all current existing transactions was finished. 107 Follow results occure: 108 E_INIT : All requests on this implementation are refused. 109 It's your decision to react in a right way. 110 111 E_WORK : The object can work now. The full functionality is available. 112 113 E_BEFORECLOSE : The object start the closing mechanism ... but sometimes 114 e.g. the dispose() method need to call some private methods. 115 These some special methods should use E_SOFTEXCEPTIONS or ignore 116 E_INCLOSE as returned reason for E_NOEXCEPTIONS to detect this special case! 117 118 E_CLOSE : Object is already dead! All further requests will be refused. 119 It's your decision to react in a right way. 120 121 @seealso - 122 123 @param "eMode", is the new mode - but we don't accept setting mode in wrong order! 124 @return - 125 126 @onerror We do nothing. 127 *//*-*****************************************************************************************************/ 128 void TransactionManager::setWorkingMode( EWorkingMode eMode ) 129 { 130 // Safe member access. 131 ::osl::ClearableMutexGuard aAccessGuard( m_aAccessLock ); 132 sal_Bool bWaitFor = sal_False ; 133 // Change working mode first! 134 if ( 135 ( m_eWorkingMode == E_INIT && eMode == E_WORK ) || 136 ( m_eWorkingMode == E_WORK && eMode == E_BEFORECLOSE ) || 137 ( m_eWorkingMode == E_BEFORECLOSE && eMode == E_CLOSE ) || 138 ( m_eWorkingMode == E_CLOSE && eMode == E_INIT ) 139 ) 140 { 141 m_eWorkingMode = eMode; 142 if( m_eWorkingMode == E_BEFORECLOSE || m_eWorkingMode == E_CLOSE ) 143 { 144 bWaitFor = sal_True; 145 } 146 } 147 148 // Wait for current existing transactions then! 149 // (Only necessary for changing to E_BEFORECLOSE or E_CLOSE! ... 150 // otherwise; if you wait at setting E_WORK another thrad could finish a acquire-call during our unlock() and wait() call 151 // ... and we will wait forever here!!!) 152 // Don't forget to release access mutex before. 153 aAccessGuard.clear(); 154 if( bWaitFor == sal_True ) 155 { 156 m_aBarrier.wait(); 157 } 158 } 159 160 /*-****************************************************************************************************//** 161 @interface ITransactionManager 162 @short get current working mode 163 @descr If you stand in your close() or init() method ... but don't know 164 if you called more then ones(!) ... you can use this function to get 165 right information. 166 e.g: You have a method init() which is used to change working mode from 167 E_INIT to E_WORK and should be used to initialize some member too ... 168 What should you do: 169 170 void init( sal_Int32 nValue ) 171 { 172 // Reject this call if our transaction manager say: "Object already initialized!" 173 // Otherwise initialize your member. 174 if( m_aTransactionManager.getWorkingMode() == E_INIT ) 175 { 176 // Object is uninitialized ... 177 // Make member access threadsafe! 178 ResetableGuard aGuard( m_aMutex ); 179 180 // Check working mode again .. because anozï¿œther instance could be faster. 181 // (It's possible to set this guard at first of this method too!) 182 if( m_aTransactionManager.getWorkingMode() == E_INIT ) 183 { 184 m_aMember = nValue; 185 186 // Object is initialized now ... set working mode to E_WORK! 187 m_aTransactionManager.setWorkingMode( E_WORK ); 188 } 189 } 190 } 191 192 @seealso method setWorkingMode() 193 194 @param - 195 @return Current set mode. 196 197 @onerror No error should occure. 198 *//*-*****************************************************************************************************/ 199 EWorkingMode TransactionManager::getWorkingMode() const 200 { 201 // Synchronize access to internal member! 202 ::osl::MutexGuard aAccessLock( m_aAccessLock ); 203 return m_eWorkingMode; 204 } 205 206 /*-****************************************************************************************************//** 207 @interface ITransactionManager 208 @short start new transaction 209 @descr A guard should use this method to start a new transaction. He should looks for rejected 210 calls to by using parameter eMode and eReason. 211 If call was not rejected your transaction will be non breakable during releasing your transaction 212 guard! BUT ... your code isn't threadsafe then! It's a transaction manager only .... 213 214 @seealso method unregisterTransaction() 215 216 @param "eMode" ,used to enable/disable throwing exceptions automatically for rejected calls 217 @param "eReason" ,reason for rejected calls if eMode=E_NOEXCEPTIONS 218 @return - 219 220 @onerror - 221 *//*-*****************************************************************************************************/ 222 void TransactionManager::registerTransaction( EExceptionMode eMode, ERejectReason& eReason ) throw( css::uno::RuntimeException, css::lang::DisposedException ) 223 { 224 // Look for rejected calls first. 225 // If call was refused we throw some exceptions or do nothing! 226 // It depends from given parameter eMode. 227 if( isCallRejected( eReason ) == sal_True ) 228 { 229 impl_throwExceptions( eMode, eReason ); 230 } 231 232 // BUT if no exception was thrown ... (may be eMode = E_SOFTEXCEPTIONS!) 233 // we must register this transaction too! 234 // Don't use "else" or a new scope here!!! 235 236 // Safe access to internal member. 237 ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 238 239 #ifdef ENABLE_MUTEXDEBUG 240 LOG_ASSERT2( m_nTransactionCount<0, "TransactionManager::acquire()", "Wrong ref count detected!" ) 241 #endif 242 243 // Register this new transaction. 244 // If it is the first one .. close gate to disable changing of working mode. 245 ++m_nTransactionCount; 246 if( m_nTransactionCount == 1 ) 247 { 248 m_aBarrier.close(); 249 } 250 } 251 252 /*-****************************************************************************************************//** 253 @interface ITransactionManager 254 @short finish transaction 255 @descr A guard should call this method to release current transaction. 256 257 @seealso method registerTransaction() 258 259 @param - 260 @return - 261 262 @onerror - 263 *//*-*****************************************************************************************************/ 264 void TransactionManager::unregisterTransaction() throw( css::uno::RuntimeException, css::lang::DisposedException ) 265 { 266 // This call could not rejected! 267 // Safe access to internal member. 268 ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 269 270 #ifdef ENABLE_MUTEXDEBUG 271 LOG_ASSERT2( m_nTransactionCount<=0, "TransactionManager::release()", "Wrong ref count detected!" ) 272 #endif 273 274 // Deregister this transaction. 275 // If it was the last one ... open gate to enable changing of working mode! 276 // (see setWorkingMode()) 277 278 --m_nTransactionCount; 279 if( m_nTransactionCount == 0 ) 280 { 281 m_aBarrier.open(); 282 } 283 } 284 285 /*-****************************************************************************************************//** 286 @interface ITransactionManager 287 @short look for rejected calls 288 @descr Sometimes user need a possibility to get information about rejected calls 289 without starting a transaction! 290 291 @seealso - 292 293 @param "eReason" returns reason of a rejected call 294 @return true if call was rejected, false otherwise 295 296 @onerror We return false. 297 *//*-*****************************************************************************************************/ 298 sal_Bool TransactionManager::isCallRejected( ERejectReason& eReason ) const 299 { 300 // This call must safe access to internal member only. 301 // Set "possible reason" for return and check reject-state then! 302 // User should look for return value first - reason then ... 303 ::osl::MutexGuard aAccessGuard( m_aAccessLock ); 304 switch( m_eWorkingMode ) 305 { 306 case E_INIT : eReason = E_UNINITIALIZED ; 307 break; 308 case E_WORK : eReason = E_NOREASON ; 309 break; 310 case E_BEFORECLOSE : eReason = E_INCLOSE ; 311 break; 312 case E_CLOSE : eReason = E_CLOSED ; 313 break; 314 } 315 return( eReason!=E_NOREASON ); 316 } 317 318 /*-****************************************************************************************************//** 319 @short throw any exceptions for rejected calls 320 @descr If user whish to use our automatically exception mode we use this impl-method. 321 We check all combinations of eReason and eExceptionMode and throw right exception with some 322 descriptions for recipient of it. 323 324 @seealso method registerTransaction() 325 @seealso enum ERejectReason 326 @seealso enum EExceptionMode 327 328 @param "eReason" , reason for rejected call 329 @param "eMode" , exception mode - set by user 330 @return - 331 332 @onerror - 333 *//*-*****************************************************************************************************/ 334 void TransactionManager::impl_throwExceptions( EExceptionMode eMode, ERejectReason eReason ) const throw( css::uno::RuntimeException, css::lang::DisposedException ) 335 { 336 if( eMode != E_NOEXCEPTIONS ) 337 { 338 switch( eReason ) 339 { 340 case E_UNINITIALIZED : if( eMode == E_HARDEXCEPTIONS ) 341 { 342 // Help programmer to find out, why this exception is thrown! 343 LOG_ERROR( "TransactionManager...", "Owner instance not right initialized yet. Call was rejected! Normaly it's an algorithm error ... wrong usin of class!" ) 344 //ATTENTION: temp. disabled - till all bad code positions are detected and changed! */ 345 // throw css::uno::RuntimeException( DECLARE_ASCII("TransactionManager...\nOwner instance not right initialized yet. Call was rejected! Normaly it's an algorithm error ... wrong usin of class!\n" ), css::uno::Reference< css::uno::XInterface >() ); 346 } 347 break; 348 case E_INCLOSE : if( eMode == E_HARDEXCEPTIONS ) 349 { 350 // Help programmer to find out, why this exception is thrown! 351 LOG_ERROR( "TransactionManager...", "Owner instance stand in close method. Call was rejected!" ) 352 throw css::lang::DisposedException( DECLARE_ASCII("TransactionManager...\nOwner instance stand in close method. Call was rejected!\n" ), css::uno::Reference< css::uno::XInterface >() ); 353 } 354 break; 355 case E_CLOSED : { 356 // Help programmer to find out, why this exception is thrown! 357 LOG_ERROR( "TransactionManager...", "Owner instance already closed. Call was rejected!" ) 358 throw css::lang::DisposedException( DECLARE_ASCII("TransactionManager...\nOwner instance already closed. Call was rejected!\n" ), css::uno::Reference< css::uno::XInterface >() ); 359 } 360 case E_NOREASON : { 361 // Help programmer to find out 362 LOG_ERROR( "TransactionManager...", "Impossible case E_NOREASON!" ) 363 } 364 break; 365 default: break; // nothing to do 366 } 367 } 368 } 369 370 } // namespace framework 371