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_chart2.hxx"
26 #include "LifeTime.hxx"
27 #include "macros.hxx"
28 #include <osl/diagnose.h>
29
30 #include <com/sun/star/util/XModifyListener.hpp>
31 #include <com/sun/star/util/XCloseListener.hpp>
32
33 using namespace ::com::sun::star;
34
35 namespace apphelper
36 {
37 //--------------------------
38
LifeTimeManager(lang::XComponent * pComponent,sal_Bool bLongLastingCallsCancelable)39 LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, sal_Bool bLongLastingCallsCancelable )
40 : m_aListenerContainer( m_aAccessMutex )
41 , m_pComponent(pComponent)
42 , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable)
43 {
44 impl_init();
45 }
46
impl_init()47 void LifeTimeManager::impl_init()
48 {
49 m_bDisposed = sal_False;
50 m_bInDispose = sal_False;
51 m_nAccessCount = 0;
52 m_nLongLastingCallCount = 0;
53 m_aNoAccessCountCondition.set();
54 m_aNoLongLastingCallCountCondition.set();
55 }
56
~LifeTimeManager()57 LifeTimeManager::~LifeTimeManager()
58 {
59 }
60
impl_isDisposed(bool bAssert)61 bool LifeTimeManager::impl_isDisposed( bool bAssert )
62 {
63 if( m_bDisposed || m_bInDispose )
64 {
65 if( bAssert )
66 {
67 OSL_ENSURE( sal_False, "This component is already disposed " );
68 (void)(bAssert);
69 }
70 return sal_True;
71 }
72 return sal_False;
73 }
74 sal_Bool LifeTimeManager
impl_canStartApiCall()75 ::impl_canStartApiCall()
76 {
77 if( impl_isDisposed() )
78 return sal_False; //behave passive if already disposed
79
80 //mutex is acquired
81 return sal_True;
82 }
83
84 void LifeTimeManager
impl_registerApiCall(sal_Bool bLongLastingCall)85 ::impl_registerApiCall(sal_Bool bLongLastingCall)
86 {
87 //only allowed if not disposed
88 //do not acquire the mutex here because it will be acquired already
89 m_nAccessCount++;
90 if(m_nAccessCount==1)
91 //@todo? is it ok to wake some threads here while we have acquired the mutex?
92 m_aNoAccessCountCondition.reset();
93
94 if(bLongLastingCall)
95 m_nLongLastingCallCount++;
96 if(m_nLongLastingCallCount==1)
97 m_aNoLongLastingCallCountCondition.reset();
98 }
99 void LifeTimeManager
impl_unregisterApiCall(sal_Bool bLongLastingCall)100 ::impl_unregisterApiCall(sal_Bool bLongLastingCall)
101 {
102 //Mutex needs to be acquired exactly ones
103 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
104
105 OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
106 m_nAccessCount--;
107 if(bLongLastingCall)
108 m_nLongLastingCallCount--;
109 if( m_nLongLastingCallCount==0 )
110 {
111 m_aNoLongLastingCallCountCondition.set();
112 }
113 if( m_nAccessCount== 0)
114 {
115 m_aNoAccessCountCondition.set();
116 impl_apiCallCountReachedNull();
117
118 }
119 }
120
121 sal_Bool LifeTimeManager
dispose()122 ::dispose() throw(uno::RuntimeException)
123 {
124 //hold no mutex
125 {
126 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
127
128 if( m_bDisposed || m_bInDispose )
129 {
130 OSL_TRACE( "This component is already disposed " );
131 return sal_False; //behave passive if already disposed
132 }
133
134 m_bInDispose = true;
135 //adding any listener is not allowed anymore
136 //new calls will not be accepted
137 //still running calls have the freedom to finish their work without crash
138 }
139 //no mutex is acquired
140
141 //--do the disposing of listeners after calling this method
142 {
143 uno::Reference< lang::XComponent > xComponent =
144 uno::Reference< lang::XComponent >(m_pComponent);;
145 if(xComponent.is())
146 {
147 // notify XCLoseListeners
148 lang::EventObject aEvent( xComponent );
149 m_aListenerContainer.disposeAndClear( aEvent );
150 }
151 }
152
153 //no mutex is acquired
154 {
155 osl::ClearableGuard< osl::Mutex > aGuard( m_aAccessMutex );
156 OSL_ENSURE( !m_bDisposed, "dispose was called already" );
157 m_bDisposed = sal_True;
158 aGuard.clear();
159 }
160 //no mutex is acquired
161
162 //wait until all still running calls have finished
163 //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed
164 m_aNoAccessCountCondition.wait();
165
166 //we are the only ones working on our data now
167
168 return sal_True;
169 //--release all resources and references after calling this method successful
170 }
171
172 //-----------------------------------------------------------------
173
CloseableLifeTimeManager(::com::sun::star::util::XCloseable * pCloseable,::com::sun::star::lang::XComponent * pComponent,sal_Bool bLongLastingCallsCancelable)174 CloseableLifeTimeManager::CloseableLifeTimeManager( ::com::sun::star::util::XCloseable* pCloseable
175 , ::com::sun::star::lang::XComponent* pComponent
176 , sal_Bool bLongLastingCallsCancelable )
177 : LifeTimeManager( pComponent, bLongLastingCallsCancelable )
178 , m_pCloseable(pCloseable)
179 {
180 impl_init();
181 }
182
~CloseableLifeTimeManager()183 CloseableLifeTimeManager::~CloseableLifeTimeManager()
184 {
185 }
186
impl_isDisposedOrClosed(bool bAssert)187 bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert )
188 {
189 if( impl_isDisposed( bAssert ) )
190 return sal_True;
191
192 if( m_bClosed )
193 {
194 if( bAssert )
195 {
196 OSL_ENSURE( sal_False, "This object is already closed" );
197 (void)(bAssert);//avoid warnings
198 }
199 return sal_True;
200 }
201 return sal_False;
202 }
203
204 sal_Bool CloseableLifeTimeManager
g_close_startTryClose(sal_Bool bDeliverOwnership)205 ::g_close_startTryClose(sal_Bool bDeliverOwnership)
206 throw ( uno::Exception )
207 {
208 //no mutex is allowed to be acquired
209 {
210 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
211 if( impl_isDisposedOrClosed(false) )
212 return sal_False;
213
214 //Mutex needs to be acquired exactly ones; will be released inbetween
215 if( !impl_canStartApiCall() )
216 return sal_False;
217 //mutex is acquired
218
219 //not closed already -> we try to close again
220 m_bInTryClose = sal_True;
221 m_aEndTryClosingCondition.reset();
222
223 impl_registerApiCall(sal_False);
224 }
225
226 //------------------------------------------------
227 //no mutex is acquired
228
229 //only remove listener calls will be worked on until end of tryclose
230 //all other new calls will wait till end of try close // @todo? is that really ok
231
232 //?? still running calls have the freedom to finish their work without crash
233
234 try
235 {
236 uno::Reference< util::XCloseable > xCloseable =
237 uno::Reference< util::XCloseable >(m_pCloseable);;
238 if(xCloseable.is())
239 {
240 //--call queryClosing on all registered close listeners
241 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
242 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
243 if( pIC )
244 {
245 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
246 lang::EventObject aEvent( xCloseable );
247 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
248 while( aIt.hasMoreElements() )
249 {
250 uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY );
251 if(xCloseListener.is())
252 xCloseListener->queryClosing( aEvent, bDeliverOwnership );
253 }
254 }
255 }
256 }
257 catch( uno::Exception& ex )
258 {
259 //no mutex is acquired
260 g_close_endTryClose(bDeliverOwnership, sal_False);
261 (void)(ex);
262 throw;
263 }
264 return sal_True;
265 }
266
267 void CloseableLifeTimeManager
g_close_endTryClose(sal_Bool bDeliverOwnership,sal_Bool)268 ::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ )
269 {
270 //this method is called, if the try to close was not successful
271 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
272 impl_setOwnership( bDeliverOwnership, sal_False );
273
274 m_bInTryClose = sal_False;
275 m_aEndTryClosingCondition.set();
276
277 //Mutex needs to be acquired exactly ones
278 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
279 impl_unregisterApiCall(sal_False);
280 }
281
282 sal_Bool CloseableLifeTimeManager
g_close_isNeedToCancelLongLastingCalls(sal_Bool bDeliverOwnership,util::CloseVetoException & ex)283 ::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership, util::CloseVetoException& ex )
284 throw ( util::CloseVetoException )
285 {
286 //this method is called when no closelistener has had a veto during queryclosing
287 //the method returns false, if nothing stands against closing anymore
288 //it returns true, if some longlasting calls are running, which might be cancelled
289 //it throws the given exception, if long calls are running but not cancelable
290
291 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
292 //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
293 if( !m_nLongLastingCallCount )
294 return sal_False;
295
296 if(m_bLongLastingCallsCancelable)
297 return sal_True;
298
299 impl_setOwnership( bDeliverOwnership, sal_True );
300
301 m_bInTryClose = sal_False;
302 m_aEndTryClosingCondition.set();
303
304 //Mutex needs to be acquired exactly ones
305 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
306 impl_unregisterApiCall(sal_False);
307
308 throw ex;
309 }
310
311 void CloseableLifeTimeManager
g_close_endTryClose_doClose()312 ::g_close_endTryClose_doClose()
313 {
314 //this method is called, if the try to close was successful
315 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
316
317 m_bInTryClose = sal_False;
318 m_aEndTryClosingCondition.set();
319
320 //Mutex needs to be acquired exactly ones
321 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
322 impl_unregisterApiCall(sal_False);
323 impl_doClose();
324 }
325
326 void CloseableLifeTimeManager
impl_setOwnership(sal_Bool bDeliverOwnership,sal_Bool bMyVeto)327 ::impl_setOwnership( sal_Bool bDeliverOwnership, sal_Bool bMyVeto )
328 {
329 m_bOwnership = bDeliverOwnership && bMyVeto;
330 m_bOwnershipIsWellKnown = sal_True;
331 }
332 sal_Bool CloseableLifeTimeManager
impl_shouldCloseAtNextChance()333 ::impl_shouldCloseAtNextChance()
334 {
335 return m_bOwnership;
336 }
337
338 void CloseableLifeTimeManager
impl_apiCallCountReachedNull()339 ::impl_apiCallCountReachedNull()
340 {
341 //Mutex needs to be acquired exactly ones
342 //mutex will be released inbetween in impl_doClose()
343 if( m_pCloseable && impl_shouldCloseAtNextChance() )
344 impl_doClose();
345 }
346
347 void CloseableLifeTimeManager
impl_doClose()348 ::impl_doClose()
349 {
350 //Mutex needs to be acquired exactly ones before calling impl_doClose()
351
352 if(m_bClosed)
353 return; //behave as passive as possible, if disposed or closed already
354 if( m_bDisposed || m_bInDispose )
355 return; //behave as passive as possible, if disposed or closed already
356
357 //--------
358 m_bClosed = sal_True;
359
360 NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex );
361 //mutex is not acquired, mutex will be reacquired at the end of this method automatically
362
363 uno::Reference< util::XCloseable > xCloseable=NULL;
364 try
365 {
366 xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);;
367 if(xCloseable.is())
368 {
369 //--call notifyClosing on all registered close listeners
370 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
371 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
372 if( pIC )
373 {
374 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
375 lang::EventObject aEvent( xCloseable );
376 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
377 while( aIt.hasMoreElements() )
378 {
379 uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY );
380 if( xListener.is() )
381 xListener->notifyClosing( aEvent );
382 }
383 }
384 }
385 }
386 catch( uno::Exception& ex )
387 {
388 ASSERT_EXCEPTION( ex );
389 }
390
391 if(xCloseable.is())
392 {
393 uno::Reference< lang::XComponent > xComponent =
394 uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY );
395 if(xComponent.is())
396 {
397 OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
398 xComponent->dispose();
399 }
400 }
401 //mutex will be reacquired in destructor of aNegativeGuard
402 }
403
404 sal_Bool CloseableLifeTimeManager
g_addCloseListener(const uno::Reference<util::XCloseListener> & xListener)405 ::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
406 throw(uno::RuntimeException)
407 {
408 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
409 //Mutex needs to be acquired exactly ones; will be released inbetween
410 if( !impl_canStartApiCall() )
411 return sal_False;
412 //mutex is acquired
413
414 m_aListenerContainer.addInterface( ::getCppuType((const uno::Reference< util::XCloseListener >*)0),xListener );
415 m_bOwnership = sal_False;
416 return sal_True;
417 }
418
419 sal_Bool CloseableLifeTimeManager
impl_canStartApiCall()420 ::impl_canStartApiCall()
421 {
422 //Mutex needs to be acquired exactly ones before calling this method
423 //the mutex will be released inbetween and reacquired
424
425 if( impl_isDisposed() )
426 return sal_False; //behave passive if already disposed
427 if( m_bClosed )
428 return sal_False; //behave passive if closing is already done
429
430 //during try-close most calls need to wait for the decision
431 while( m_bInTryClose )
432 {
433 //if someone tries to close this object at the moment
434 //we need to wait for his end because the result of the preceding call
435 //is relevant for our behaviour here
436
437 m_aAccessMutex.release();
438 m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing
439 m_aAccessMutex.acquire();
440 if( m_bDisposed || m_bInDispose || m_bClosed )
441 return sal_False; //return if closed already
442 }
443 //mutex is acquired
444 return sal_True;
445 }
446
447 //--------------------------
448
449 sal_Bool LifeTimeGuard
startApiCall(sal_Bool bLongLastingCall)450 ::startApiCall(sal_Bool bLongLastingCall)
451 {
452 //Mutex needs to be acquired exactly ones; will be released inbetween
453 //mutex is requiered due to constructor of LifeTimeGuard
454
455 OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
456 if(m_bCallRegistered)
457 return sal_False;
458
459 //Mutex needs to be acquired exactly ones; will be released inbetween
460 if( !m_rManager.impl_canStartApiCall() )
461 return sal_False;
462 //mutex is acquired
463
464 m_bCallRegistered = sal_True;
465 m_bLongLastingCallRegistered = bLongLastingCall;
466 m_rManager.impl_registerApiCall(bLongLastingCall);
467 return sal_True;
468 }
469
~LifeTimeGuard()470 LifeTimeGuard::~LifeTimeGuard()
471 {
472 try
473 {
474 //do acquire the mutex if it was cleared before
475 osl::MutexGuard g(m_rManager.m_aAccessMutex);
476 if(m_bCallRegistered)
477 {
478 //Mutex needs to be acquired exactly ones
479 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
480 m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered);
481 }
482 }
483 catch( uno::Exception& ex )
484 {
485 //@todo ? allow a uno::RuntimeException from dispose to travel through??
486 ex.Context.is(); //to avoid compilation warnings
487 }
488 }
489
490 /*
491 the XCloseable::close method has to be implemented in the following way:
492 ::close
493 {
494 //hold no mutex
495
496 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
497 return;
498 //no mutex is acquired
499
500 // At the end of this method may we must dispose ourself ...
501 // and may nobody from outside hold a reference to us ...
502 // then it's a good idea to do that by ourself.
503 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
504
505 //the listeners have had no veto
506 //check whether we self can close
507 {
508 util::CloseVetoException aVetoException = util::CloseVetoException(
509 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
510 "the model itself could not be closed" ) )
511 , static_cast< ::cppu::OWeakObject* >(this));
512
513 if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) )
514 {
515 ////you can empty this block, if you never start longlasting calls or
516 ////if your longlasting calls are per default not cancelable (check how you have constructed your LifeTimeManager)
517
518 sal_Bool bLongLastingCallsAreCanceled = sal_False;
519 try
520 {
521 //try to cancel running longlasting calls
522 //// @todo
523 }
524 catch( uno::Exception& ex )
525 {
526 //// @todo
527 //do not throw anything here!! (without endTryClose)
528 }
529 //if not successful canceled
530 if(!bLongLastingCallsAreCanceled)
531 {
532 m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True );
533 throw aVetoException;
534 }
535 }
536
537 }
538 m_aLifeTimeManager.g_close_endTryClose_doClose();
539 }
540 */
541
542 }//end namespace apphelper
543