1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: LifeTime.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
33 #include "LifeTime.hxx"
35 #include <osl/diagnose.h>
37 #include <com/sun/star/util/XModifyListener.hpp>
38 #include <com/sun/star/util/XCloseListener.hpp>
40 using namespace ::com::sun::star
;
44 //--------------------------
46 LifeTimeManager::LifeTimeManager( lang::XComponent
* pComponent
, sal_Bool bLongLastingCallsCancelable
)
47 : m_aListenerContainer( m_aAccessMutex
)
48 , m_pComponent(pComponent
)
49 , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable
)
54 void LifeTimeManager::impl_init()
56 m_bDisposed
= sal_False
;
57 m_bInDispose
= sal_False
;
59 m_nLongLastingCallCount
= 0;
60 m_aNoAccessCountCondition
.set();
61 m_aNoLongLastingCallCountCondition
.set();
64 LifeTimeManager::~LifeTimeManager()
68 sal_Bool LifeTimeManager
71 if( m_bDisposed
|| m_bInDispose
)
73 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 sal_Bool CloseableLifeTimeManager
192 ::impl_isDisposedOrClosed()
194 if( impl_isDisposed() )
199 OSL_ENSURE( sal_False
, "This object is already closed" );
205 sal_Bool CloseableLifeTimeManager
206 ::g_close_startTryClose(sal_Bool bDeliverOwnership
)
207 throw ( uno::Exception
)
209 //no mutex is allowed to be acquired
211 osl::ResettableGuard
< osl::Mutex
> aGuard( m_aAccessMutex
);
213 //Mutex needs to be acquired exactly ones; will be released inbetween
214 if( !impl_canStartApiCall() )
218 //not closed already -> we try to close again
219 m_bInTryClose
= sal_True
;
220 m_aEndTryClosingCondition
.reset();
222 impl_registerApiCall(sal_False
);
225 //------------------------------------------------
226 //no mutex is acquired
228 //only remove listener calls will be worked on until end of tryclose
229 //all other new calls will wait till end of try close // @todo? is that really ok
231 //?? still running calls have the freedom to finish their work without crash
235 uno::Reference
< util::XCloseable
> xCloseable
=
236 uno::Reference
< util::XCloseable
>(m_pCloseable
);;
239 //--call queryClosing on all registered close listeners
240 ::cppu::OInterfaceContainerHelper
* pIC
= m_aListenerContainer
.getContainer(
241 ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0) );;
244 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
245 lang::EventObject
aEvent( xCloseable
);
246 ::cppu::OInterfaceIteratorHelper
aIt( *pIC
);
247 while( aIt
.hasMoreElements() )
249 uno::Reference
< util::XCloseListener
> xCloseListener( aIt
.next(), uno::UNO_QUERY
);
250 if(xCloseListener
.is())
251 xCloseListener
->queryClosing( aEvent
, bDeliverOwnership
);
256 catch( uno::Exception
& ex
)
258 //no mutex is acquired
259 g_close_endTryClose(bDeliverOwnership
, sal_False
);
266 void CloseableLifeTimeManager
267 ::g_close_endTryClose(sal_Bool bDeliverOwnership
, sal_Bool
/* bMyVeto */ )
269 //this method is called, if the try to close was not successfull
270 osl::Guard
< osl::Mutex
> aGuard( m_aAccessMutex
);
271 impl_setOwnership( bDeliverOwnership
, sal_False
);
273 m_bInTryClose
= sal_False
;
274 m_aEndTryClosingCondition
.set();
276 //Mutex needs to be acquired exactly ones
277 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
278 impl_unregisterApiCall(sal_False
);
281 sal_Bool CloseableLifeTimeManager
282 ::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership
, util::CloseVetoException
& ex
)
283 throw ( util::CloseVetoException
)
285 //this method is called when no closelistener has had a veto during queryclosing
286 //the method returns false, if nothing stands against closing anymore
287 //it returns true, if some longlasting calls are running, which might be cancelled
288 //it throws the given exception, if long calls are running but not cancelable
290 osl::Guard
< osl::Mutex
> aGuard( m_aAccessMutex
);
291 //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
292 if( !m_nLongLastingCallCount
)
295 if(m_bLongLastingCallsCancelable
)
298 impl_setOwnership( bDeliverOwnership
, sal_True
);
300 m_bInTryClose
= sal_False
;
301 m_aEndTryClosingCondition
.set();
303 //Mutex needs to be acquired exactly ones
304 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
305 impl_unregisterApiCall(sal_False
);
310 void CloseableLifeTimeManager
311 ::g_close_endTryClose_doClose()
313 //this method is called, if the try to close was successfull
314 osl::ResettableGuard
< osl::Mutex
> aGuard( m_aAccessMutex
);
316 m_bInTryClose
= sal_False
;
317 m_aEndTryClosingCondition
.set();
319 //Mutex needs to be acquired exactly ones
320 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
321 impl_unregisterApiCall(sal_False
);
325 void CloseableLifeTimeManager
326 ::impl_setOwnership( sal_Bool bDeliverOwnership
, sal_Bool bMyVeto
)
328 m_bOwnership
= bDeliverOwnership
&& bMyVeto
;
329 m_bOwnershipIsWellKnown
= sal_True
;
331 sal_Bool CloseableLifeTimeManager
332 ::impl_shouldCloseAtNextChance()
337 void CloseableLifeTimeManager
338 ::impl_apiCallCountReachedNull()
340 //Mutex needs to be acquired exactly ones
341 //mutex will be released inbetween in impl_doClose()
342 if( m_pCloseable
&& impl_shouldCloseAtNextChance() )
346 void CloseableLifeTimeManager
349 //Mutex needs to be acquired exactly ones before calling impl_doClose()
352 return; //behave as passive as possible, if disposed or closed already
353 if( m_bDisposed
|| m_bInDispose
)
354 return; //behave as passive as possible, if disposed or closed already
357 m_bClosed
= sal_True
;
359 NegativeGuard
< osl::Mutex
> aNegativeGuard( m_aAccessMutex
);
360 //mutex is not acquired, mutex will be reacquired at the end of this method automatically
362 uno::Reference
< util::XCloseable
> xCloseable
=NULL
;
365 xCloseable
= uno::Reference
< util::XCloseable
>(m_pCloseable
);;
368 //--call notifyClosing on all registered close listeners
369 ::cppu::OInterfaceContainerHelper
* pIC
= m_aListenerContainer
.getContainer(
370 ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0) );;
373 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
374 lang::EventObject
aEvent( xCloseable
);
375 ::cppu::OInterfaceIteratorHelper
aIt( *pIC
);
376 while( aIt
.hasMoreElements() )
377 (static_cast< util::XCloseListener
*>(aIt
.next()))->notifyClosing( aEvent
);
381 catch( uno::Exception
& ex
)
383 ASSERT_EXCEPTION( ex
);
388 uno::Reference
< lang::XComponent
> xComponent
=
389 uno::Reference
< lang::XComponent
>( xCloseable
, uno::UNO_QUERY
);
392 OSL_ENSURE( m_bClosed
, "a not closed component will be disposed " );
393 xComponent
->dispose();
396 //mutex will be reacquired in destructor of aNegativeGuard
399 sal_Bool CloseableLifeTimeManager
400 ::g_addCloseListener( const uno::Reference
< util::XCloseListener
> & xListener
)
401 throw(uno::RuntimeException
)
403 osl::Guard
< osl::Mutex
> aGuard( m_aAccessMutex
);
404 //Mutex needs to be acquired exactly ones; will be released inbetween
405 if( !impl_canStartApiCall() )
409 m_aListenerContainer
.addInterface( ::getCppuType((const uno::Reference
< util::XCloseListener
>*)0),xListener
);
410 m_bOwnership
= sal_False
;
414 sal_Bool CloseableLifeTimeManager
415 ::impl_canStartApiCall()
417 //Mutex needs to be acquired exactly ones before calling this method
418 //the mutex will be released inbetween and reacquired
420 if( impl_isDisposed() )
421 return sal_False
; //behave passive if already disposed
423 return sal_False
; //behave passive if closing is already done
425 //during try-close most calls need to wait for the decision
426 while( m_bInTryClose
)
428 //if someone tries to close this object at the moment
429 //we need to wait for his end because the result of the preceding call
430 //is relevant for our behaviour here
432 m_aAccessMutex
.release();
433 m_aEndTryClosingCondition
.wait(); //@todo??? this may block??? try closing
434 m_aAccessMutex
.acquire();
435 if( m_bDisposed
|| m_bInDispose
|| m_bClosed
)
436 return sal_False
; //return if closed already
442 //--------------------------
444 sal_Bool LifeTimeGuard
445 ::startApiCall(sal_Bool bLongLastingCall
)
447 //Mutex needs to be acquired exactly ones; will be released inbetween
448 //mutex is requiered due to constructor of LifeTimeGuard
450 OSL_ENSURE( !m_bCallRegistered
, "this method is only allowed ones" );
451 if(m_bCallRegistered
)
454 //Mutex needs to be acquired exactly ones; will be released inbetween
455 if( !m_rManager
.impl_canStartApiCall() )
459 m_bCallRegistered
= sal_True
;
460 m_bLongLastingCallRegistered
= bLongLastingCall
;
461 m_rManager
.impl_registerApiCall(bLongLastingCall
);
465 LifeTimeGuard::~LifeTimeGuard()
469 //do acquire the mutex if it was cleared before
470 osl::MutexGuard
g(m_rManager
.m_aAccessMutex
);
471 if(m_bCallRegistered
)
473 //Mutex needs to be acquired exactly ones
474 //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
475 m_rManager
.impl_unregisterApiCall(m_bLongLastingCallRegistered
);
478 catch( uno::Exception
& ex
)
480 //@todo ? allow a uno::RuntimeException from dispose to travel through??
481 ex
.Context
.is(); //to avoid compilation warnings
486 the XCloseable::close method has to be implemented in the following way:
491 if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
493 //no mutex is acquired
495 // At the end of this method may we must dispose ourself ...
496 // and may nobody from outside hold a reference to us ...
497 // then it's a good idea to do that by ourself.
498 uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
500 //the listeners have had no veto
501 //check wether we self can close
503 util::CloseVetoException aVetoException = util::CloseVetoException(
504 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
505 "the model itself could not be closed" ) )
506 , static_cast< ::cppu::OWeakObject* >(this));
508 if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) )
510 ////you can empty this block, if you never start longlasting calls or
511 ////if your longlasting calls are per default not cancelable (check how you have constructed your LifeTimeManager)
513 sal_Bool bLongLastingCallsAreCanceled = sal_False;
516 //try to cancel running longlasting calls
519 catch( uno::Exception& ex )
522 //do not throw anything here!! (without endTryClose)
524 //if not successful canceled
525 if(!bLongLastingCallsAreCanceled)
527 m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True );
528 throw aVetoException;
533 m_aLifeTimeManager.g_close_endTryClose_doClose();
537 }//end namespace apphelper