1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
31 //_________________________________________________________________________________________________________________
33 //_________________________________________________________________________________________________________________
34 #include <threadhelp/transactionmanager.hxx>
35 #include <threadhelp/resetableguard.hxx>
36 #include <macros/debug.hxx>
38 #include <macros/generic.hxx>
40 //_________________________________________________________________________________________________________________
42 //_________________________________________________________________________________________________________________
43 #include <com/sun/star/lang/DisposedException.hpp>
44 //_________________________________________________________________________________________________________________
46 //_________________________________________________________________________________________________________________
48 //_________________________________________________________________________________________________________________
50 //_________________________________________________________________________________________________________________
52 //_________________________________________________________________________________________________________________
54 //_________________________________________________________________________________________________________________
58 //_________________________________________________________________________________________________________________
60 //_________________________________________________________________________________________________________________
62 //_________________________________________________________________________________________________________________
63 // non exported declarations
64 //_________________________________________________________________________________________________________________
66 //_________________________________________________________________________________________________________________
68 //_________________________________________________________________________________________________________________
70 /*-************************************************************************************************************//**
72 @descr Initialize instance with right start values for correct working.
80 *//*-*************************************************************************************************************/
81 TransactionManager::TransactionManager()
82 : m_eWorkingMode ( E_INIT
)
83 , m_nTransactionCount ( 0 )
88 /*-************************************************************************************************************//**
98 *//*-*************************************************************************************************************/
99 TransactionManager::~TransactionManager()
103 /*-****************************************************************************************************//**
104 @interface ITransactionManager
105 @short set new working mode
106 @descr These implementation knows for states of working: E_INIT, E_WORK, E_CLOSING, E_CLOSE
107 You can step during this ones only from the left to the right side and start at left side again!
108 (This is neccessary e.g. for refcounted objects!)
109 This call will block till all current existing transactions was finished.
110 Follow results occure:
111 E_INIT : All requests on this implementation are refused.
112 It's your decision to react in a right way.
114 E_WORK : The object can work now. The full functionality is available.
116 E_BEFORECLOSE : The object start the closing mechanism ... but sometimes
117 e.g. the dispose() method need to call some private methods.
118 These some special methods should use E_SOFTEXCEPTIONS or ignore
119 E_INCLOSE as returned reason for E_NOEXCEPTIONS to detect this special case!
121 E_CLOSE : Object is already dead! All further requests will be refused.
122 It's your decision to react in a right way.
126 @param "eMode", is the new mode - but we don't accept setting mode in wrong order!
129 @onerror We do nothing.
130 *//*-*****************************************************************************************************/
131 void TransactionManager::setWorkingMode( EWorkingMode eMode
)
133 // Safe member access.
134 ::osl::ClearableMutexGuard
aAccessGuard( m_aAccessLock
);
135 sal_Bool bWaitFor
= sal_False
;
136 // Change working mode first!
138 ( m_eWorkingMode
== E_INIT
&& eMode
== E_WORK
) ||
139 ( m_eWorkingMode
== E_WORK
&& eMode
== E_BEFORECLOSE
) ||
140 ( m_eWorkingMode
== E_BEFORECLOSE
&& eMode
== E_CLOSE
) ||
141 ( m_eWorkingMode
== E_CLOSE
&& eMode
== E_INIT
)
144 m_eWorkingMode
= eMode
;
145 if( m_eWorkingMode
== E_BEFORECLOSE
|| m_eWorkingMode
== E_CLOSE
)
151 // Wait for current existing transactions then!
152 // (Only neccessary for changing to E_BEFORECLOSE or E_CLOSE! ...
153 // otherwise; if you wait at setting E_WORK another thrad could finish a acquire-call during our unlock() and wait() call
154 // ... and we will wait forever here!!!)
155 // Don't forget to release access mutex before.
156 aAccessGuard
.clear();
157 if( bWaitFor
== sal_True
)
163 /*-****************************************************************************************************//**
164 @interface ITransactionManager
165 @short get current working mode
166 @descr If you stand in your close() or init() method ... but don't know
167 if you called more then ones(!) ... you can use this function to get
169 e.g: You have a method init() which is used to change working mode from
170 E_INIT to E_WORK and should be used to initialize some member too ...
173 void init( sal_Int32 nValue )
175 // Reject this call if our transaction manager say: "Object already initialized!"
176 // Otherwise initialize your member.
177 if( m_aTransactionManager.getWorkingMode() == E_INIT )
179 // Object is uninitialized ...
180 // Make member access threadsafe!
181 ResetableGuard aGuard( m_aMutex );
183 // Check working mode again .. because anoz�ther instance could be faster.
184 // (It's possible to set this guard at first of this method too!)
185 if( m_aTransactionManager.getWorkingMode() == E_INIT )
189 // Object is initialized now ... set working mode to E_WORK!
190 m_aTransactionManager.setWorkingMode( E_WORK );
195 @seealso method setWorkingMode()
198 @return Current set mode.
200 @onerror No error should occure.
201 *//*-*****************************************************************************************************/
202 EWorkingMode
TransactionManager::getWorkingMode() const
204 // Synchronize access to internal member!
205 ::osl::MutexGuard
aAccessLock( m_aAccessLock
);
206 return m_eWorkingMode
;
209 /*-****************************************************************************************************//**
210 @interface ITransactionManager
211 @short start new transaction
212 @descr A guard should use this method to start a new transaction. He should looks for rejected
213 calls to by using parameter eMode and eReason.
214 If call was not rejected your transaction will be non breakable during releasing your transaction
215 guard! BUT ... your code isn't threadsafe then! It's a transaction manager only ....
217 @seealso method unregisterTransaction()
219 @param "eMode" ,used to enable/disable throwing exceptions automaticly for rejected calls
220 @param "eReason" ,reason for rejected calls if eMode=E_NOEXCEPTIONS
224 *//*-*****************************************************************************************************/
225 void TransactionManager::registerTransaction( EExceptionMode eMode
, ERejectReason
& eReason
) throw( css::uno::RuntimeException
, css::lang::DisposedException
)
227 // Look for rejected calls first.
228 // If call was refused we throw some exceptions or do nothing!
229 // It depends from given parameter eMode.
230 if( isCallRejected( eReason
) == sal_True
)
232 impl_throwExceptions( eMode
, eReason
);
235 // BUT if no exception was thrown ... (may be eMode = E_SOFTEXCEPTIONS!)
236 // we must register this transaction too!
237 // Don't use "else" or a new scope here!!!
239 // Safe access to internal member.
240 ::osl::MutexGuard
aAccessGuard( m_aAccessLock
);
242 #ifdef ENABLE_MUTEXDEBUG
243 LOG_ASSERT2( m_nTransactionCount
<0, "TransactionManager::acquire()", "Wrong ref count detected!" )
246 // Register this new transaction.
247 // If it is the first one .. close gate to disable changing of working mode.
248 ++m_nTransactionCount
;
249 if( m_nTransactionCount
== 1 )
255 /*-****************************************************************************************************//**
256 @interface ITransactionManager
257 @short finish transaction
258 @descr A guard should call this method to release current transaction.
260 @seealso method registerTransaction()
266 *//*-*****************************************************************************************************/
267 void TransactionManager::unregisterTransaction() throw( css::uno::RuntimeException
, css::lang::DisposedException
)
269 // This call could not rejected!
270 // Safe access to internal member.
271 ::osl::MutexGuard
aAccessGuard( m_aAccessLock
);
273 #ifdef ENABLE_MUTEXDEBUG
274 LOG_ASSERT2( m_nTransactionCount
<=0, "TransactionManager::release()", "Wrong ref count detected!" )
277 // Deregister this transaction.
278 // If it was the last one ... open gate to enable changing of working mode!
279 // (see setWorkingMode())
281 --m_nTransactionCount
;
282 if( m_nTransactionCount
== 0 )
288 /*-****************************************************************************************************//**
289 @interface ITransactionManager
290 @short look for rejected calls
291 @descr Sometimes user need a possibility to get information about rejected calls
292 without starting a transaction!
296 @param "eReason" returns reason of a rejected call
297 @return true if call was rejected, false otherwise
299 @onerror We return false.
300 *//*-*****************************************************************************************************/
301 sal_Bool
TransactionManager::isCallRejected( ERejectReason
& eReason
) const
303 // This call must safe access to internal member only.
304 // Set "possible reason" for return and check reject-state then!
305 // User should look for return value first - reason then ...
306 ::osl::MutexGuard
aAccessGuard( m_aAccessLock
);
307 switch( m_eWorkingMode
)
309 case E_INIT
: eReason
= E_UNINITIALIZED
;
311 case E_WORK
: eReason
= E_NOREASON
;
313 case E_BEFORECLOSE
: eReason
= E_INCLOSE
;
315 case E_CLOSE
: eReason
= E_CLOSED
;
318 return( eReason
!=E_NOREASON
);
321 /*-****************************************************************************************************//**
322 @short throw any exceptions for rejected calls
323 @descr If user whish to use our automaticly exception mode we use this impl-method.
324 We check all combinations of eReason and eExceptionMode and throw right exception with some
325 descriptions for recipient of it.
327 @seealso method registerTransaction()
328 @seealso enum ERejectReason
329 @seealso enum EExceptionMode
331 @param "eReason" , reason for rejected call
332 @param "eMode" , exception mode - set by user
336 *//*-*****************************************************************************************************/
337 void TransactionManager::impl_throwExceptions( EExceptionMode eMode
, ERejectReason eReason
) const throw( css::uno::RuntimeException
, css::lang::DisposedException
)
339 if( eMode
!= E_NOEXCEPTIONS
)
343 case E_UNINITIALIZED
: if( eMode
== E_HARDEXCEPTIONS
)
345 // Help programmer to find out, why this exception is thrown!
346 LOG_ERROR( "TransactionManager...", "Owner instance not right initialized yet. Call was rejected! Normaly it's an algorithm error ... wrong usin of class!" )
347 //ATTENTION: temp. disabled - till all bad code positions are detected and changed! */
348 // 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 >() );
351 case E_INCLOSE
: if( eMode
== E_HARDEXCEPTIONS
)
353 // Help programmer to find out, why this exception is thrown!
354 LOG_ERROR( "TransactionManager...", "Owner instance stand in close method. Call was rejected!" )
355 throw css::lang::DisposedException( DECLARE_ASCII("TransactionManager...\nOwner instance stand in close method. Call was rejected!\n" ), css::uno::Reference
< css::uno::XInterface
>() );
359 // Help programmer to find out, why this exception is thrown!
360 LOG_ERROR( "TransactionManager...", "Owner instance already closed. Call was rejected!" )
361 throw css::lang::DisposedException( DECLARE_ASCII("TransactionManager...\nOwner instance already closed. Call was rejected!\n" ), css::uno::Reference
< css::uno::XInterface
>() );
364 // Help programmer to find out
365 LOG_ERROR( "TransactionManager...", "Impossible case E_NOREASON!" )
368 default: break; // nothing to do
373 } // namespace framework