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