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 *//*-*************************************************************************************************************/
TransactionManager()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 *//*-*************************************************************************************************************/
~TransactionManager()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 Following results occur:
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 *//*-*****************************************************************************************************/
setWorkingMode(EWorkingMode eMode)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 occur.
198 *//*-*****************************************************************************************************/
getWorkingMode() const199 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 *//*-*****************************************************************************************************/
registerTransaction(EExceptionMode eMode,ERejectReason & eReason)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 *//*-*****************************************************************************************************/
unregisterTransaction()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 *//*-*****************************************************************************************************/
isCallRejected(ERejectReason & eReason) const298 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 *//*-*****************************************************************************************************/
impl_throwExceptions(EExceptionMode eMode,ERejectReason eReason) const334 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! Normally it's an algorithm error ... wrong using 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! Normally it's an algorithm error ... wrong using 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