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