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_comphelper.hxx" 30 31 #include "comphelper_module.hxx" 32 33 #include <com/sun/star/util/XCloseBroadcaster.hpp> 34 #include <com/sun/star/util/XCloseable.hpp> 35 #include <com/sun/star/lang/DisposedException.hpp> 36 #include <com/sun/star/lang/IllegalArgumentException.hpp> 37 #include <com/sun/star/frame/XDesktop.hpp> 38 #include <com/sun/star/frame/DoubleInitializationException.hpp> 39 #include <com/sun/star/frame/DoubleInitializationException.hpp> 40 #include <com/sun/star/beans/XPropertySet.hpp> 41 42 #include "instancelocker.hxx" 43 44 using namespace ::com::sun::star; 45 46 47 // ==================================================================== 48 // OInstanceLocker 49 // ==================================================================== 50 51 // -------------------------------------------------------- 52 OInstanceLocker::OInstanceLocker( const uno::Reference< uno::XComponentContext >& xContext ) 53 : m_xContext( xContext ) 54 , m_pLockListener( NULL ) 55 , m_pListenersContainer( NULL ) 56 , m_bDisposed( sal_False ) 57 , m_bInitialized( sal_False ) 58 { 59 } 60 61 // -------------------------------------------------------- 62 OInstanceLocker::~OInstanceLocker() 63 { 64 if ( !m_bDisposed ) 65 { 66 m_refCount++; // to call dispose 67 try { 68 dispose(); 69 } 70 catch ( uno::RuntimeException& ) 71 {} 72 } 73 74 if ( m_pListenersContainer ) 75 { 76 delete m_pListenersContainer; 77 m_pListenersContainer = NULL; 78 } 79 } 80 81 // XComponent 82 // -------------------------------------------------------- 83 void SAL_CALL OInstanceLocker::dispose() 84 throw (uno::RuntimeException) 85 { 86 ::osl::MutexGuard aGuard( m_aMutex ); 87 88 if ( m_bDisposed ) 89 throw lang::DisposedException(); 90 91 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); 92 if ( m_pListenersContainer ) 93 m_pListenersContainer->disposeAndClear( aSource ); 94 95 if ( m_xLockListener.is() ) 96 { 97 if ( m_pLockListener ) 98 { 99 m_pLockListener->Dispose(); 100 m_pLockListener = NULL; 101 } 102 m_xLockListener = uno::Reference< uno::XInterface >(); 103 } 104 105 m_bDisposed = sal_True; 106 } 107 108 // -------------------------------------------------------- 109 void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) 110 throw (uno::RuntimeException) 111 { 112 ::osl::MutexGuard aGuard( m_aMutex ); 113 if ( m_bDisposed ) 114 throw lang::DisposedException(); // TODO 115 116 if ( !m_pListenersContainer ) 117 m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex ); 118 119 m_pListenersContainer->addInterface( xListener ); 120 } 121 122 // -------------------------------------------------------- 123 void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) 124 throw (uno::RuntimeException) 125 { 126 ::osl::MutexGuard aGuard( m_aMutex ); 127 if ( m_pListenersContainer ) 128 m_pListenersContainer->removeInterface( xListener ); 129 } 130 131 // XInitialization 132 // -------------------------------------------------------- 133 void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments ) 134 throw (uno::Exception, uno::RuntimeException) 135 { 136 ::osl::MutexGuard aGuard( m_aMutex ); 137 if ( m_bInitialized ) 138 throw frame::DoubleInitializationException(); 139 140 if ( m_bDisposed ) 141 throw lang::DisposedException(); // TODO 142 143 if ( !m_refCount ) 144 throw uno::RuntimeException(); // the object must be refcounted already! 145 146 uno::Reference< uno::XInterface > xInstance; 147 uno::Reference< embed::XActionsApproval > xApproval; 148 sal_Int32 nModes = 0; 149 150 try 151 { 152 sal_Int32 nLen = aArguments.getLength(); 153 if ( nLen < 2 || nLen > 3 ) 154 throw lang::IllegalArgumentException( 155 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ), 156 uno::Reference< uno::XInterface >(), 157 0 ); 158 159 if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() ) 160 throw lang::IllegalArgumentException( 161 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ), 162 uno::Reference< uno::XInterface >(), 163 0 ); 164 165 if ( 166 !( aArguments[1] >>= nModes ) || 167 ( 168 !( nModes & embed::Actions::PREVENT_CLOSE ) && 169 !( nModes & embed::Actions::PREVENT_TERMINATION ) 170 ) 171 ) 172 { 173 throw lang::IllegalArgumentException( 174 ::rtl::OUString( 175 RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ), 176 uno::Reference< uno::XInterface >(), 177 0 ); 178 } 179 180 if ( nLen == 3 && !( aArguments[2] >>= xApproval ) ) 181 throw lang::IllegalArgumentException( 182 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ), 183 uno::Reference< uno::XInterface >(), 184 0 ); 185 186 m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ), 187 xInstance, 188 nModes, 189 xApproval ); 190 m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( m_pLockListener ) ); 191 m_pLockListener->Init(); 192 } 193 catch( uno::Exception& ) 194 { 195 dispose(); 196 throw; 197 } 198 199 m_bInitialized = sal_True; 200 } 201 202 203 // XServiceInfo 204 // -------------------------------------------------------- 205 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName( ) 206 throw (uno::RuntimeException) 207 { 208 return getImplementationName_static(); 209 } 210 211 // -------------------------------------------------------- 212 ::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName ) 213 throw (uno::RuntimeException) 214 { 215 uno::Sequence< ::rtl::OUString > aSeq = getSupportedServiceNames(); 216 217 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) 218 if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) 219 return sal_True; 220 221 return sal_False; 222 } 223 224 // -------------------------------------------------------- 225 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames() 226 throw (uno::RuntimeException) 227 { 228 return getSupportedServiceNames_static(); 229 } 230 231 // Static methods 232 // -------------------------------------------------------- 233 uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames_static() 234 { 235 const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) ); 236 return uno::Sequence< rtl::OUString >( &aServiceName, 1 ); 237 } 238 239 // -------------------------------------------------------- 240 ::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName_static() 241 { 242 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) ); 243 } 244 245 // -------------------------------------------------------- 246 uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::Create( 247 const uno::Reference< uno::XComponentContext >& rxContext ) 248 { 249 return static_cast< cppu::OWeakObject * >( new OInstanceLocker( rxContext ) ); 250 } 251 252 253 254 // ==================================================================== 255 // OLockListener 256 // ==================================================================== 257 258 // -------------------------------------------------------- 259 OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper, 260 const uno::Reference< uno::XInterface >& xInstance, 261 sal_Int32 nMode, 262 const uno::Reference< embed::XActionsApproval > xApproval ) 263 : m_xInstance( xInstance ) 264 , m_xApproval( xApproval ) 265 , m_xWrapper( xWrapper ) 266 , m_bDisposed( sal_False ) 267 , m_bInitialized( sal_False ) 268 , m_nMode( nMode ) 269 { 270 } 271 272 // -------------------------------------------------------- 273 OLockListener::~OLockListener() 274 { 275 } 276 277 // -------------------------------------------------------- 278 void OLockListener::Dispose() 279 { 280 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 281 282 if ( m_bDisposed ) 283 return; 284 285 if ( m_nMode & embed::Actions::PREVENT_CLOSE ) 286 { 287 try 288 { 289 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY ); 290 if ( xCloseBroadcaster.is() ) 291 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); 292 293 uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY ); 294 if ( xCloseable.is() ) 295 xCloseable->close( sal_True ); 296 } 297 catch( uno::Exception& ) 298 {} 299 } 300 301 if ( m_nMode & embed::Actions::PREVENT_TERMINATION ) 302 { 303 try 304 { 305 uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); 306 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); 307 } 308 catch( uno::Exception& ) 309 {} 310 } 311 312 m_xInstance = uno::Reference< uno::XInterface >(); 313 m_bDisposed = sal_True; 314 } 315 316 // XEventListener 317 // -------------------------------------------------------- 318 void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent ) 319 throw (uno::RuntimeException) 320 { 321 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 322 323 // object is disposed 324 if ( aEvent.Source == m_xInstance ) 325 { 326 // the object does not listen for anything any more 327 m_nMode = 0; 328 329 // dispose the wrapper; 330 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); 331 aGuard.clear(); 332 if ( xComponent.is() ) 333 { 334 try { xComponent->dispose(); } 335 catch( uno::Exception& ){} 336 } 337 } 338 } 339 340 341 // XCloseListener 342 // -------------------------------------------------------- 343 void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool ) 344 throw (util::CloseVetoException, uno::RuntimeException) 345 { 346 // GetsOwnership parameter is always ignored, the user of the service must close the object always 347 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 348 if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) ) 349 { 350 try 351 { 352 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; 353 354 // unlock the mutex here 355 aGuard.clear(); 356 357 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) ) 358 throw util::CloseVetoException(); 359 } 360 catch( util::CloseVetoException& ) 361 { 362 // rethrow this exception 363 throw; 364 } 365 catch( uno::Exception& ) 366 { 367 // no action should be done 368 } 369 } 370 } 371 372 // -------------------------------------------------------- 373 void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent ) 374 throw (uno::RuntimeException) 375 { 376 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 377 378 // object is closed, no reason to listen 379 if ( aEvent.Source == m_xInstance ) 380 { 381 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY ); 382 if ( xCloseBroadcaster.is() ) 383 { 384 xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); 385 m_nMode &= ~embed::Actions::PREVENT_CLOSE; 386 if ( !m_nMode ) 387 { 388 // dispose the wrapper; 389 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); 390 aGuard.clear(); 391 if ( xComponent.is() ) 392 { 393 try { xComponent->dispose(); } 394 catch( uno::Exception& ){} 395 } 396 } 397 } 398 } 399 } 400 401 402 // XTerminateListener 403 // -------------------------------------------------------- 404 void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent ) 405 throw (frame::TerminationVetoException, uno::RuntimeException) 406 { 407 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 408 if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) ) 409 { 410 try 411 { 412 uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; 413 414 // unlock the mutex here 415 aGuard.clear(); 416 417 if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) ) 418 throw frame::TerminationVetoException(); 419 } 420 catch( frame::TerminationVetoException& ) 421 { 422 // rethrow this exception 423 throw; 424 } 425 catch( uno::Exception& ) 426 { 427 // no action should be done 428 } 429 } 430 } 431 432 // -------------------------------------------------------- 433 void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent ) 434 throw (uno::RuntimeException) 435 { 436 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 437 438 // object is terminated, no reason to listen 439 if ( aEvent.Source == m_xInstance ) 440 { 441 uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY ); 442 if ( xDesktop.is() ) 443 { 444 try 445 { 446 xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); 447 m_nMode &= ~embed::Actions::PREVENT_TERMINATION; 448 if ( !m_nMode ) 449 { 450 // dispose the wrapper; 451 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); 452 aGuard.clear(); 453 if ( xComponent.is() ) 454 { 455 try { xComponent->dispose(); } 456 catch( uno::Exception& ){} 457 } 458 } 459 } 460 catch( uno::Exception& ) 461 {} 462 } 463 } 464 } 465 466 467 // XInitialization 468 // -------------------------------------------------------- 469 sal_Bool OLockListener::Init() 470 { 471 ::osl::ResettableMutexGuard aGuard( m_aMutex ); 472 473 if ( m_bDisposed || m_bInitialized ) 474 return sal_False; 475 476 try 477 { 478 if ( m_nMode & embed::Actions::PREVENT_CLOSE ) 479 { 480 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW ); 481 xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) ); 482 } 483 484 if ( m_nMode & embed::Actions::PREVENT_TERMINATION ) 485 { 486 uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); 487 xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); 488 } 489 } 490 catch( uno::Exception& ) 491 { 492 // dispose the wrapper; 493 uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); 494 aGuard.clear(); 495 if ( xComponent.is() ) 496 { 497 try { xComponent->dispose(); } 498 catch( uno::Exception& ){} 499 } 500 501 throw; 502 } 503 504 m_bInitialized = sal_True; 505 506 return sal_True; 507 } 508 509 void createRegistryInfo_OInstanceLocker() 510 { 511 static ::comphelper::module::OAutoRegistration< OInstanceLocker > aAutoRegistration; 512 } 513