merged tag ooo/OOO330_m14
[LibreOffice.git] / chart2 / source / tools / LifeTime.cxx
blob444e894a101da92e02098dd327003313e2440e2d
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_chart2.hxx"
30 #include "LifeTime.hxx"
31 #include "macros.hxx"
32 #include <osl/diagnose.h>
34 #include <com/sun/star/util/XModifyListener.hpp>
35 #include <com/sun/star/util/XCloseListener.hpp>
37 using namespace ::com::sun::star;
39 namespace apphelper
41 //--------------------------
43 LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, sal_Bool bLongLastingCallsCancelable )
44 : m_aListenerContainer( m_aAccessMutex )
45 , m_pComponent(pComponent)
46 , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable)
48 impl_init();
51 void LifeTimeManager::impl_init()
53 m_bDisposed = sal_False;
54 m_bInDispose = sal_False;
55 m_nAccessCount = 0;
56 m_nLongLastingCallCount = 0;
57 m_aNoAccessCountCondition.set();
58 m_aNoLongLastingCallCountCondition.set();
61 LifeTimeManager::~LifeTimeManager()
65 bool LifeTimeManager::impl_isDisposed( bool bAssert )
67 if( m_bDisposed || m_bInDispose )
69 if( bAssert )
71 OSL_ENSURE( sal_False, "This component is already disposed " );
72 (void)(bAssert);
74 return sal_True;
76 return sal_False;
78 sal_Bool LifeTimeManager
79 ::impl_canStartApiCall()
81 if( impl_isDisposed() )
82 return sal_False; //behave passive if already disposed
84 //mutex is acquired
85 return sal_True;
88 void LifeTimeManager
89 ::impl_registerApiCall(sal_Bool bLongLastingCall)
91 //only allowed if not disposed
92 //do not acquire the mutex here because it will be acquired already
93 m_nAccessCount++;
94 if(m_nAccessCount==1)
95 //@todo? is it ok to wake some threads here while we have acquired the mutex?
96 m_aNoAccessCountCondition.reset();
98 if(bLongLastingCall)
99 m_nLongLastingCallCount++;
100 if(m_nLongLastingCallCount==1)
101 m_aNoLongLastingCallCountCondition.reset();
103 void LifeTimeManager
104 ::impl_unregisterApiCall(sal_Bool bLongLastingCall)
106 //Mutex needs to be acquired exactly ones
107 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
109 OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
110 m_nAccessCount--;
111 if(bLongLastingCall)
112 m_nLongLastingCallCount--;
113 if( m_nLongLastingCallCount==0 )
115 m_aNoLongLastingCallCountCondition.set();
117 if( m_nAccessCount== 0)
119 m_aNoAccessCountCondition.set();
120 impl_apiCallCountReachedNull();
125 sal_Bool LifeTimeManager
126 ::dispose() throw(uno::RuntimeException)
128 //hold no mutex
130 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
132 if( m_bDisposed || m_bInDispose )
134 OSL_TRACE( "This component is already disposed " );
135 return sal_False; //behave passive if already disposed
138 m_bInDispose = true;
139 //adding any listener is not allowed anymore
140 //new calls will not be accepted
141 //still running calls have the freedom to finish their work without crash
143 //no mutex is acquired
145 //--do the disposing of listeners after calling this method
147 uno::Reference< lang::XComponent > xComponent =
148 uno::Reference< lang::XComponent >(m_pComponent);;
149 if(xComponent.is())
151 // notify XCLoseListeners
152 lang::EventObject aEvent( xComponent );
153 m_aListenerContainer.disposeAndClear( aEvent );
157 //no mutex is acquired
159 osl::ClearableGuard< osl::Mutex > aGuard( m_aAccessMutex );
160 OSL_ENSURE( !m_bDisposed, "dispose was called already" );
161 m_bDisposed = sal_True;
162 aGuard.clear();
164 //no mutex is acquired
166 //wait until all still running calls have finished
167 //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed
168 m_aNoAccessCountCondition.wait();
170 //we are the only ones working on our data now
172 return sal_True;
173 //--release all resources and references after calling this method successful
176 //-----------------------------------------------------------------
178 CloseableLifeTimeManager::CloseableLifeTimeManager( ::com::sun::star::util::XCloseable* pCloseable
179 , ::com::sun::star::lang::XComponent* pComponent
180 , sal_Bool bLongLastingCallsCancelable )
181 : LifeTimeManager( pComponent, bLongLastingCallsCancelable )
182 , m_pCloseable(pCloseable)
184 impl_init();
187 CloseableLifeTimeManager::~CloseableLifeTimeManager()
191 bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert )
193 if( impl_isDisposed( bAssert ) )
194 return sal_True;
196 if( m_bClosed )
198 if( bAssert )
200 OSL_ENSURE( sal_False, "This object is already closed" );
201 (void)(bAssert);//avoid warnings
203 return sal_True;
205 return sal_False;
208 sal_Bool CloseableLifeTimeManager
209 ::g_close_startTryClose(sal_Bool bDeliverOwnership)
210 throw ( uno::Exception )
212 //no mutex is allowed to be acquired
214 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
215 if( impl_isDisposedOrClosed(false) )
216 return sal_False;
218 //Mutex needs to be acquired exactly ones; will be released inbetween
219 if( !impl_canStartApiCall() )
220 return sal_False;
221 //mutex is acquired
223 //not closed already -> we try to close again
224 m_bInTryClose = sal_True;
225 m_aEndTryClosingCondition.reset();
227 impl_registerApiCall(sal_False);
230 //------------------------------------------------
231 //no mutex is acquired
233 //only remove listener calls will be worked on until end of tryclose
234 //all other new calls will wait till end of try close // @todo? is that really ok
236 //?? still running calls have the freedom to finish their work without crash
240 uno::Reference< util::XCloseable > xCloseable =
241 uno::Reference< util::XCloseable >(m_pCloseable);;
242 if(xCloseable.is())
244 //--call queryClosing on all registered close listeners
245 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
246 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
247 if( pIC )
249 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
250 lang::EventObject aEvent( xCloseable );
251 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
252 while( aIt.hasMoreElements() )
254 uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY );
255 if(xCloseListener.is())
256 xCloseListener->queryClosing( aEvent, bDeliverOwnership );
261 catch( uno::Exception& ex )
263 //no mutex is acquired
264 g_close_endTryClose(bDeliverOwnership, sal_False);
265 (void)(ex);
266 throw;
268 return sal_True;
271 void CloseableLifeTimeManager
272 ::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ )
274 //this method is called, if the try to close was not successfull
275 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
276 impl_setOwnership( bDeliverOwnership, sal_False );
278 m_bInTryClose = sal_False;
279 m_aEndTryClosingCondition.set();
281 //Mutex needs to be acquired exactly ones
282 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
283 impl_unregisterApiCall(sal_False);
286 sal_Bool CloseableLifeTimeManager
287 ::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership, util::CloseVetoException& ex )
288 throw ( util::CloseVetoException )
290 //this method is called when no closelistener has had a veto during queryclosing
291 //the method returns false, if nothing stands against closing anymore
292 //it returns true, if some longlasting calls are running, which might be cancelled
293 //it throws the given exception, if long calls are running but not cancelable
295 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
296 //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
297 if( !m_nLongLastingCallCount )
298 return sal_False;
300 if(m_bLongLastingCallsCancelable)
301 return sal_True;
303 impl_setOwnership( bDeliverOwnership, sal_True );
305 m_bInTryClose = sal_False;
306 m_aEndTryClosingCondition.set();
308 //Mutex needs to be acquired exactly ones
309 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
310 impl_unregisterApiCall(sal_False);
312 throw ex;
315 void CloseableLifeTimeManager
316 ::g_close_endTryClose_doClose()
318 //this method is called, if the try to close was successfull
319 osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
321 m_bInTryClose = sal_False;
322 m_aEndTryClosingCondition.set();
324 //Mutex needs to be acquired exactly ones
325 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
326 impl_unregisterApiCall(sal_False);
327 impl_doClose();
330 void CloseableLifeTimeManager
331 ::impl_setOwnership( sal_Bool bDeliverOwnership, sal_Bool bMyVeto )
333 m_bOwnership = bDeliverOwnership && bMyVeto;
334 m_bOwnershipIsWellKnown = sal_True;
336 sal_Bool CloseableLifeTimeManager
337 ::impl_shouldCloseAtNextChance()
339 return m_bOwnership;
342 void CloseableLifeTimeManager
343 ::impl_apiCallCountReachedNull()
345 //Mutex needs to be acquired exactly ones
346 //mutex will be released inbetween in impl_doClose()
347 if( m_pCloseable && impl_shouldCloseAtNextChance() )
348 impl_doClose();
351 void CloseableLifeTimeManager
352 ::impl_doClose()
354 //Mutex needs to be acquired exactly ones before calling impl_doClose()
356 if(m_bClosed)
357 return; //behave as passive as possible, if disposed or closed already
358 if( m_bDisposed || m_bInDispose )
359 return; //behave as passive as possible, if disposed or closed already
361 //--------
362 m_bClosed = sal_True;
364 NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex );
365 //mutex is not acquired, mutex will be reacquired at the end of this method automatically
367 uno::Reference< util::XCloseable > xCloseable=NULL;
370 xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);;
371 if(xCloseable.is())
373 //--call notifyClosing on all registered close listeners
374 ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
375 ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
376 if( pIC )
378 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
379 lang::EventObject aEvent( xCloseable );
380 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
381 while( aIt.hasMoreElements() )
383 uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY );
384 if( xListener.is() )
385 xListener->notifyClosing( aEvent );
390 catch( uno::Exception& ex )
392 ASSERT_EXCEPTION( ex );
395 if(xCloseable.is())
397 uno::Reference< lang::XComponent > xComponent =
398 uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY );
399 if(xComponent.is())
401 OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
402 xComponent->dispose();
405 //mutex will be reacquired in destructor of aNegativeGuard
408 sal_Bool CloseableLifeTimeManager
409 ::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
410 throw(uno::RuntimeException)
412 osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
413 //Mutex needs to be acquired exactly ones; will be released inbetween
414 if( !impl_canStartApiCall() )
415 return sal_False;
416 //mutex is acquired
418 m_aListenerContainer.addInterface( ::getCppuType((const uno::Reference< util::XCloseListener >*)0),xListener );
419 m_bOwnership = sal_False;
420 return sal_True;
423 sal_Bool CloseableLifeTimeManager
424 ::impl_canStartApiCall()
426 //Mutex needs to be acquired exactly ones before calling this method
427 //the mutex will be released inbetween and reacquired
429 if( impl_isDisposed() )
430 return sal_False; //behave passive if already disposed
431 if( m_bClosed )
432 return sal_False; //behave passive if closing is already done
434 //during try-close most calls need to wait for the decision
435 while( m_bInTryClose )
437 //if someone tries to close this object at the moment
438 //we need to wait for his end because the result of the preceding call
439 //is relevant for our behaviour here
441 m_aAccessMutex.release();
442 m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing
443 m_aAccessMutex.acquire();
444 if( m_bDisposed || m_bInDispose || m_bClosed )
445 return sal_False; //return if closed already
447 //mutex is acquired
448 return sal_True;
451 //--------------------------
453 sal_Bool LifeTimeGuard
454 ::startApiCall(sal_Bool bLongLastingCall)
456 //Mutex needs to be acquired exactly ones; will be released inbetween
457 //mutex is requiered due to constructor of LifeTimeGuard
459 OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
460 if(m_bCallRegistered)
461 return sal_False;
463 //Mutex needs to be acquired exactly ones; will be released inbetween
464 if( !m_rManager.impl_canStartApiCall() )
465 return sal_False;
466 //mutex is acquired
468 m_bCallRegistered = sal_True;
469 m_bLongLastingCallRegistered = bLongLastingCall;
470 m_rManager.impl_registerApiCall(bLongLastingCall);
471 return sal_True;
474 LifeTimeGuard::~LifeTimeGuard()
478 //do acquire the mutex if it was cleared before
479 osl::MutexGuard g(m_rManager.m_aAccessMutex);
480 if(m_bCallRegistered)
482 //Mutex needs to be acquired exactly ones
483 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
484 m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered);
487 catch( uno::Exception& ex )
489 //@todo ? allow a uno::RuntimeException from dispose to travel through??
490 ex.Context.is(); //to avoid compilation warnings
495 the XCloseable::close method has to be implemented in the following way:
496 ::close
498 //hold no mutex
500 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
501 return;
502 //no mutex is acquired
504 // At the end of this method may we must dispose ourself ...
505 // and may nobody from outside hold a reference to us ...
506 // then it's a good idea to do that by ourself.
507 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
509 //the listeners have had no veto
510 //check wether we self can close
512 util::CloseVetoException aVetoException = util::CloseVetoException(
513 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
514 "the model itself could not be closed" ) )
515 , static_cast< ::cppu::OWeakObject* >(this));
517 if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) )
519 ////you can empty this block, if you never start longlasting calls or
520 ////if your longlasting calls are per default not cancelable (check how you have constructed your LifeTimeManager)
522 sal_Bool bLongLastingCallsAreCanceled = sal_False;
525 //try to cancel running longlasting calls
526 //// @todo
528 catch( uno::Exception& ex )
530 //// @todo
531 //do not throw anything here!! (without endTryClose)
533 //if not successful canceled
534 if(!bLongLastingCallsAreCanceled)
536 m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True );
537 throw aVetoException;
542 m_aLifeTimeManager.g_close_endTryClose_doClose();
546 }//end namespace apphelper