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