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"
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
;
41 //--------------------------
43 LifeTimeManager::LifeTimeManager( lang::XComponent
* pComponent
, sal_Bool bLongLastingCallsCancelable
)
44 : m_aListenerContainer( m_aAccessMutex
)
45 , m_pComponent(pComponent
)
46 , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable
)
51 void LifeTimeManager::impl_init()
53 m_bDisposed
= sal_False
;
54 m_bInDispose
= sal_False
;
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
)
71 OSL_ENSURE( sal_False
, "This component is already disposed " );
78 sal_Bool LifeTimeManager
79 ::impl_canStartApiCall()
81 if( impl_isDisposed() )
82 return sal_False
; //behave passive if already disposed
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
95 //@todo? is it ok to wake some threads here while we have acquired the mutex?
96 m_aNoAccessCountCondition
.reset();
99 m_nLongLastingCallCount
++;
100 if(m_nLongLastingCallCount
==1)
101 m_aNoLongLastingCallCountCondition
.reset();
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" );
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
)
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
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
);;
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
;
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
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
)
187 CloseableLifeTimeManager::~CloseableLifeTimeManager()
191 bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert
)
193 if( impl_isDisposed( bAssert
) )
200 OSL_ENSURE( sal_False
, "This object is already closed" );
201 (void)(bAssert
);//avoid warnings
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) )
218 //Mutex needs to be acquired exactly ones; will be released inbetween
219 if( !impl_canStartApiCall() )
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
);;
244 //--call queryClosing on all registered close listeners
245 ::cppu::OInterfaceContainerHelper
* pIC
= m_aListenerContainer
.getContainer(
246 ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0) );;
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
);
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
)
300 if(m_bLongLastingCallsCancelable
)
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
);
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
);
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()
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() )
351 void CloseableLifeTimeManager
354 //Mutex needs to be acquired exactly ones before calling impl_doClose()
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
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
);;
373 //--call notifyClosing on all registered close listeners
374 ::cppu::OInterfaceContainerHelper
* pIC
= m_aListenerContainer
.getContainer(
375 ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0) );;
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
);
385 xListener
->notifyClosing( aEvent
);
390 catch( uno::Exception
& ex
)
392 ASSERT_EXCEPTION( ex
);
397 uno::Reference
< lang::XComponent
> xComponent
=
398 uno::Reference
< lang::XComponent
>( xCloseable
, uno::UNO_QUERY
);
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() )
418 m_aListenerContainer
.addInterface( ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0),xListener
);
419 m_bOwnership
= sal_False
;
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
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
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
)
463 //Mutex needs to be acquired exactly ones; will be released inbetween
464 if( !m_rManager
.impl_canStartApiCall() )
468 m_bCallRegistered
= sal_True
;
469 m_bLongLastingCallRegistered
= bLongLastingCall
;
470 m_rManager
.impl_registerApiCall(bLongLastingCall
);
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:
500 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
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
528 catch( uno::Exception& ex )
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