xref: /aoo41x/main/chart2/source/tools/LifeTime.cxx (revision cdf0e10c)
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