xref: /trunk/main/chart2/source/tools/LifeTime.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
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>
33 
34 #include <com/sun/star/util/XModifyListener.hpp>
35 #include <com/sun/star/util/XCloseListener.hpp>
36 
37 using namespace ::com::sun::star;
38 
39 namespace apphelper
40 {
41 //--------------------------
42 
43 LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, sal_Bool bLongLastingCallsCancelable )
44     : m_aListenerContainer( m_aAccessMutex )
45     , m_pComponent(pComponent)
46     , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable)
47 {
48     impl_init();
49 }
50 
51 void LifeTimeManager::impl_init()
52 {
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();
59 }
60 
61 LifeTimeManager::~LifeTimeManager()
62 {
63 }
64 
65 bool LifeTimeManager::impl_isDisposed( bool bAssert )
66 {
67     if( m_bDisposed || m_bInDispose )
68     {
69         if( bAssert )
70         {
71             OSL_ENSURE( sal_False, "This component is already disposed " );
72             (void)(bAssert);
73         }
74         return sal_True;
75     }
76     return sal_False;
77 }
78             sal_Bool LifeTimeManager
79 ::impl_canStartApiCall()
80 {
81     if( impl_isDisposed() )
82         return sal_False; //behave passive if already disposed
83 
84     //mutex is acquired
85     return sal_True;
86 }
87 
88     void LifeTimeManager
89 ::impl_registerApiCall(sal_Bool bLongLastingCall)
90 {
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();
97 
98     if(bLongLastingCall)
99         m_nLongLastingCallCount++;
100     if(m_nLongLastingCallCount==1)
101         m_aNoLongLastingCallCountCondition.reset();
102 }
103     void LifeTimeManager
104 ::impl_unregisterApiCall(sal_Bool bLongLastingCall)
105 {
106     //Mutex needs to be acquired exactly ones
107     //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
108 
109     OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
110     m_nAccessCount--;
111     if(bLongLastingCall)
112         m_nLongLastingCallCount--;
113     if( m_nLongLastingCallCount==0 )
114     {
115         m_aNoLongLastingCallCountCondition.set();
116     }
117     if( m_nAccessCount== 0)
118     {
119         m_aNoAccessCountCondition.set();
120         impl_apiCallCountReachedNull();
121 
122     }
123 }
124 
125         sal_Bool LifeTimeManager
126 ::dispose() throw(uno::RuntimeException)
127 {
128     //hold no mutex
129     {
130         osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
131 
132         if( m_bDisposed || m_bInDispose )
133         {
134             OSL_TRACE( "This component is already disposed " );
135             return sal_False; //behave passive if already disposed
136         }
137 
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
142     }
143     //no mutex is acquired
144 
145     //--do the disposing of listeners after calling this method
146     {
147         uno::Reference< lang::XComponent > xComponent =
148             uno::Reference< lang::XComponent >(m_pComponent);;
149         if(xComponent.is())
150         {
151             // notify XCLoseListeners
152             lang::EventObject aEvent( xComponent );
153             m_aListenerContainer.disposeAndClear( aEvent );
154         }
155     }
156 
157     //no mutex is acquired
158     {
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();
163     }
164     //no mutex is acquired
165 
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();
169 
170     //we are the only ones working on our data now
171 
172     return sal_True;
173     //--release all resources and references after calling this method successful
174 }
175 
176 //-----------------------------------------------------------------
177 
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)
183 {
184     impl_init();
185 }
186 
187 CloseableLifeTimeManager::~CloseableLifeTimeManager()
188 {
189 }
190 
191 bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert )
192 {
193     if( impl_isDisposed( bAssert ) )
194         return sal_True;
195 
196     if( m_bClosed )
197     {
198         if( bAssert )
199         {
200             OSL_ENSURE( sal_False, "This object is already closed" );
201             (void)(bAssert);//avoid warnings
202         }
203         return sal_True;
204     }
205     return sal_False;
206 }
207 
208         sal_Bool CloseableLifeTimeManager
209 ::g_close_startTryClose(sal_Bool bDeliverOwnership)
210     throw ( uno::Exception )
211 {
212     //no mutex is allowed to be acquired
213     {
214         osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
215         if( impl_isDisposedOrClosed(false) )
216             return sal_False;
217 
218         //Mutex needs to be acquired exactly ones; will be released inbetween
219         if( !impl_canStartApiCall() )
220             return sal_False;
221         //mutex is acquired
222 
223         //not closed already -> we try to close again
224         m_bInTryClose = sal_True;
225         m_aEndTryClosingCondition.reset();
226 
227         impl_registerApiCall(sal_False);
228     }
229 
230     //------------------------------------------------
231     //no mutex is acquired
232 
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
235 
236     //?? still running calls have the freedom to finish their work without crash
237 
238     try
239     {
240         uno::Reference< util::XCloseable > xCloseable =
241             uno::Reference< util::XCloseable >(m_pCloseable);;
242         if(xCloseable.is())
243         {
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 )
248             {
249                 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
250                 lang::EventObject aEvent( xCloseable );
251                 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
252                 while( aIt.hasMoreElements() )
253                 {
254                     uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY );
255                     if(xCloseListener.is())
256                         xCloseListener->queryClosing( aEvent, bDeliverOwnership );
257                 }
258             }
259         }
260     }
261     catch( uno::Exception& ex )
262     {
263         //no mutex is acquired
264         g_close_endTryClose(bDeliverOwnership, sal_False);
265         (void)(ex);
266         throw;
267     }
268     return sal_True;
269 }
270 
271     void CloseableLifeTimeManager
272 ::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ )
273 {
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 );
277 
278     m_bInTryClose = sal_False;
279     m_aEndTryClosingCondition.set();
280 
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);
284 }
285 
286     sal_Bool CloseableLifeTimeManager
287 ::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership, util::CloseVetoException& ex )
288     throw ( util::CloseVetoException )
289 {
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
294 
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;
299 
300     if(m_bLongLastingCallsCancelable)
301         return sal_True;
302 
303     impl_setOwnership( bDeliverOwnership, sal_True );
304 
305     m_bInTryClose = sal_False;
306     m_aEndTryClosingCondition.set();
307 
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);
311 
312     throw ex;
313 }
314 
315     void CloseableLifeTimeManager
316 ::g_close_endTryClose_doClose()
317 {
318     //this method is called, if the try to close was successfull
319     osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
320 
321     m_bInTryClose       = sal_False;
322     m_aEndTryClosingCondition.set();
323 
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();
328 }
329 
330     void CloseableLifeTimeManager
331 ::impl_setOwnership( sal_Bool bDeliverOwnership, sal_Bool bMyVeto )
332 {
333     m_bOwnership            = bDeliverOwnership && bMyVeto;
334     m_bOwnershipIsWellKnown = sal_True;
335 }
336     sal_Bool CloseableLifeTimeManager
337 ::impl_shouldCloseAtNextChance()
338 {
339     return m_bOwnership;
340 }
341 
342     void CloseableLifeTimeManager
343 ::impl_apiCallCountReachedNull()
344 {
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();
349 }
350 
351     void CloseableLifeTimeManager
352 ::impl_doClose()
353 {
354     //Mutex needs to be acquired exactly ones before calling impl_doClose()
355 
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
360 
361     //--------
362     m_bClosed = sal_True;
363 
364     NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex );
365     //mutex is not acquired, mutex will be reacquired at the end of this method automatically
366 
367     uno::Reference< util::XCloseable > xCloseable=NULL;
368     try
369     {
370         xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);;
371         if(xCloseable.is())
372         {
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 )
377             {
378                 //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
379                 lang::EventObject aEvent( xCloseable );
380                 ::cppu::OInterfaceIteratorHelper aIt( *pIC );
381                 while( aIt.hasMoreElements() )
382                 {
383                     uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY );
384                     if( xListener.is() )
385                         xListener->notifyClosing( aEvent );
386                 }
387             }
388         }
389     }
390     catch( uno::Exception& ex )
391     {
392         ASSERT_EXCEPTION( ex );
393     }
394 
395     if(xCloseable.is())
396     {
397         uno::Reference< lang::XComponent > xComponent =
398             uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY );
399         if(xComponent.is())
400         {
401             OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
402             xComponent->dispose();
403         }
404     }
405     //mutex will be reacquired in destructor of aNegativeGuard
406 }
407 
408     sal_Bool CloseableLifeTimeManager
409 ::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
410     throw(uno::RuntimeException)
411 {
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
417 
418     m_aListenerContainer.addInterface( ::getCppuType((const uno::Reference< util::XCloseListener >*)0),xListener );
419     m_bOwnership = sal_False;
420     return sal_True;
421 }
422 
423     sal_Bool CloseableLifeTimeManager
424 ::impl_canStartApiCall()
425 {
426     //Mutex needs to be acquired exactly ones before calling this method
427     //the mutex will be released inbetween and reacquired
428 
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
433 
434     //during try-close most calls need to wait for the decision
435     while( m_bInTryClose )
436     {
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
440 
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
446     }
447     //mutex is acquired
448     return sal_True;
449 }
450 
451 //--------------------------
452 
453     sal_Bool LifeTimeGuard
454 ::startApiCall(sal_Bool bLongLastingCall)
455 {
456     //Mutex needs to be acquired exactly ones; will be released inbetween
457     //mutex is requiered due to constructor of LifeTimeGuard
458 
459     OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
460     if(m_bCallRegistered)
461         return sal_False;
462 
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
467 
468     m_bCallRegistered = sal_True;
469     m_bLongLastingCallRegistered = bLongLastingCall;
470     m_rManager.impl_registerApiCall(bLongLastingCall);
471     return sal_True;
472 }
473 
474 LifeTimeGuard::~LifeTimeGuard()
475 {
476     try
477     {
478         //do acquire the mutex if it was cleared before
479         osl::MutexGuard g(m_rManager.m_aAccessMutex);
480         if(m_bCallRegistered)
481         {
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);
485         }
486     }
487     catch( uno::Exception& ex )
488     {
489         //@todo ? allow a uno::RuntimeException from dispose to travel through??
490         ex.Context.is(); //to avoid compilation warnings
491     }
492 }
493 
494 /*
495 the XCloseable::close method has to be implemented in the following way:
496 ::close
497 {
498     //hold no mutex
499 
500     if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
501         return;
502     //no mutex is acquired
503 
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) );
508 
509     //the listeners have had no veto
510     //check wether we self can close
511     {
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));
516 
517         if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) )
518         {
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)
521 
522             sal_Bool bLongLastingCallsAreCanceled = sal_False;
523             try
524             {
525                 //try to cancel running longlasting calls
526                 //// @todo
527             }
528             catch( uno::Exception& ex )
529             {
530                 //// @todo
531                 //do not throw anything here!! (without endTryClose)
532             }
533             //if not successful canceled
534             if(!bLongLastingCallsAreCanceled)
535             {
536                 m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True );
537                 throw aVetoException;
538             }
539         }
540 
541     }
542     m_aLifeTimeManager.g_close_endTryClose_doClose();
543 }
544 */
545 
546 }//end namespace apphelper
547