From 38d57523fe03aaeb5654db42913ab703e07a7baa Mon Sep 17 00:00:00 2001 From: RĂ¼diger Timm Date: Thu, 9 Feb 2006 13:10:30 +0000 Subject: INTEGRATION: CWS fwk32 (1.1.2); FILE ADDED 2006/01/30 10:42:08 mav 1.1.2.1: #129051# allow to register close- and terminate-listener without exception support --- comphelper/source/misc/instancelocker.cxx | 530 ++++++++++++++++++++++++++++++ 1 file changed, 530 insertions(+) create mode 100644 comphelper/source/misc/instancelocker.cxx (limited to 'comphelper') diff --git a/comphelper/source/misc/instancelocker.cxx b/comphelper/source/misc/instancelocker.cxx new file mode 100644 index 000000000000..6552cb033775 --- /dev/null +++ b/comphelper/source/misc/instancelocker.cxx @@ -0,0 +1,530 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: instancelocker.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: rt $ $Date: 2006-02-09 14:10:30 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +#ifndef _COM_SUN_STAR_UTIL_XCLOSEBROADCASTER_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_ +#include +#endif + +#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_FRAME_XDESKTOP_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_FRAME_DOUBLEINITIALIZATIONEXCEPTION_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_FRAME_DOUBLEINITIALIZATIONEXCEPTION_HPP_ +#include +#endif +#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ +#include +#endif + +#include "instancelocker.hxx" + +using namespace ::com::sun::star; + + +// ==================================================================== +// OInstanceLocker +// ==================================================================== + +// -------------------------------------------------------- +OInstanceLocker::OInstanceLocker( const uno::Reference< uno::XComponentContext >& xContext ) +: m_xContext( xContext ) +, m_pLockListener( NULL ) +, m_pListenersContainer( NULL ) +, m_bDisposed( sal_False ) +, m_bInitialized( sal_False ) +{ +} + +// -------------------------------------------------------- +OInstanceLocker::~OInstanceLocker() +{ + if ( !m_bDisposed ) + { + m_refCount++; // to call dispose + try { + dispose(); + } + catch ( uno::RuntimeException& ) + {} + } + + if ( m_pListenersContainer ) + { + delete m_pListenersContainer; + m_pListenersContainer = NULL; + } +} + +// XComponent +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::dispose() + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + throw lang::DisposedException(); + + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + if ( m_pListenersContainer ) + m_pListenersContainer->disposeAndClear( aSource ); + + if ( m_xLockListener.is() ) + { + m_pLockListener->Dispose(); + m_xLockListener = uno::Reference< uno::XInterface >(); + } + + m_bDisposed = sal_True; +} + +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bDisposed ) + throw lang::DisposedException(); // TODO + + if ( !m_pListenersContainer ) + m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutex ); + + m_pListenersContainer->addInterface( xListener ); +} + +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_pListenersContainer ) + m_pListenersContainer->removeInterface( xListener ); +} + +// XInitialization +// -------------------------------------------------------- +void SAL_CALL OInstanceLocker::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw (uno::Exception, uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bInitialized ) + throw frame::DoubleInitializationException(); + + if ( m_bDisposed ) + throw lang::DisposedException(); // TODO + + if ( !m_refCount ) + throw uno::RuntimeException(); // the object must be refcounted already! + + uno::Reference< uno::XInterface > xInstance; + uno::Reference< embed::XActionsApproval > xApproval; + sal_Int32 nModes = 0; + + try + { + sal_Int32 nLen = aArguments.getLength(); + if ( nLen < 2 || nLen > 3 ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Wrong count of parameters!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + if ( !( aArguments[0] >>= xInstance ) || !xInstance.is() ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Nonempty reference is expected as the first argument!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + if ( !( aArguments[1] >>= nModes ) + || !( nModes & embed::Actions::PREVENT_CLOSE ) && !( nModes & embed::Actions::PREVENT_TERMINATION ) ) + throw lang::IllegalArgumentException( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("The correct modes set is expected as the second argument!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + uno::Any aAny = aArguments[2]; + if ( nLen == 3 && !( aArguments[2] >>= xApproval ) ) + throw lang::IllegalArgumentException( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("If the third argument is provided, it must be XActionsApproval implementation!" ) ), + uno::Reference< uno::XInterface >(), + 0 ); + + m_pLockListener = new OLockListener( uno::Reference< lang::XComponent > ( static_cast< lang::XComponent* >( this ) ), + xInstance, + nModes, + xApproval ); + m_xLockListener = uno::Reference< uno::XInterface >( static_cast< OWeakObject* >( this ) ); + m_pLockListener->Init(); + } + catch( uno::Exception& ) + { + dispose(); + throw; + } + + m_bInitialized = sal_True; +} + + +// XServiceInfo +// -------------------------------------------------------- +::rtl::OUString SAL_CALL OInstanceLocker::getImplementationName( ) + throw (uno::RuntimeException) +{ + return impl_staticGetImplementationName(); +} + +// -------------------------------------------------------- +::sal_Bool SAL_CALL OInstanceLocker::supportsService( const ::rtl::OUString& ServiceName ) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +// -------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::getSupportedServiceNames() + throw (uno::RuntimeException) +{ + return impl_staticGetSupportedServiceNames(); +} + +// Static methods +// -------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OInstanceLocker::impl_staticGetSupportedServiceNames() +{ + const rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.embed.InstanceLocker" ) ); + return uno::Sequence< rtl::OUString >( &aServiceName, 1 ); +} + +// -------------------------------------------------------- +::rtl::OUString SAL_CALL OInstanceLocker::impl_staticGetImplementationName() +{ + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.embed.InstanceLocker" ) ); +} + +// -------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OInstanceLocker::impl_staticCreateSelfInstance( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + uno::Reference< uno::XComponentContext > xContext; + uno::Reference< beans::XPropertySet > xPropSet( xServiceManager, uno::UNO_QUERY ); + if ( xPropSet.is() ) + xPropSet->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ) >>= xContext; + + if ( !xContext.is() ) + { + throw uno::RuntimeException( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unable to obtain component context from service manager!" ) ), + uno::Reference< uno::XInterface >() ); + } + + return static_cast< cppu::OWeakObject * >( new OInstanceLocker( xContext ) ); +} + + + +// ==================================================================== +// OLockListener +// ==================================================================== + +// -------------------------------------------------------- +OLockListener::OLockListener( const uno::WeakReference< lang::XComponent >& xWrapper, + const uno::Reference< uno::XInterface >& xInstance, + sal_Int8 nMode, + const uno::Reference< embed::XActionsApproval > xApproval ) +: m_xInstance( xInstance ) +, m_xApproval( xApproval ) +, m_xWrapper( xWrapper ) +, m_bDisposed( sal_False ) +, m_bInitialized( sal_False ) +, m_nMode( nMode ) +{ +} + +// -------------------------------------------------------- +OLockListener::~OLockListener() +{ +} + +// -------------------------------------------------------- +void OLockListener::Dispose() +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed ) + return; + + if ( m_nMode && embed::Actions::PREVENT_CLOSE ) + { + try + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY ); + if ( xCloseBroadcaster.is() ) + xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); + + uno::Reference< util::XCloseable > xCloseable( m_xInstance, uno::UNO_QUERY ); + if ( xCloseable.is() ) + xCloseable->close( sal_True ); + } + catch( uno::Exception& ) + {} + } + + if ( m_nMode && embed::Actions::PREVENT_TERMINATION ) + { + try + { + uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); + xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + } + catch( uno::Exception& ) + {} + } + + m_xInstance = uno::Reference< uno::XInterface >(); + m_bDisposed = sal_True; +} + +// XEventListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::disposing( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is disposed + if ( aEvent.Source == m_xInstance ) + { + // the object does not listen for anything any more + m_nMode = 0; + + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } +} + + +// XCloseListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::queryClosing( const lang::EventObject& aEvent, sal_Bool GetsOwnership ) + throw (util::CloseVetoException, uno::RuntimeException) +{ + // GetsOwnership parameter is always ignored, the user of the service must close the object always + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + if ( !m_bDisposed && aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_CLOSE ) ) + { + try + { + uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; + + // unlock the mutex here + aGuard.clear(); + + if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_CLOSE ) ) + throw util::CloseVetoException(); + } + catch( util::CloseVetoException& ) + { + // rethrow this exception + throw; + } + catch( uno::Exception& ) + { + // no action should be done + } + } +} + +// -------------------------------------------------------- +void SAL_CALL OLockListener::notifyClosing( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is closed, no reason to listen + if ( aEvent.Source == m_xInstance ) + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( aEvent.Source, uno::UNO_QUERY ); + if ( xCloseBroadcaster.is() ) + { + xCloseBroadcaster->removeCloseListener( static_cast< util::XCloseListener* >( this ) ); + m_nMode &= ~embed::Actions::PREVENT_CLOSE; + if ( !m_nMode ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } + } + } +} + + +// XTerminateListener +// -------------------------------------------------------- +void SAL_CALL OLockListener::queryTermination( const lang::EventObject& aEvent ) + throw (frame::TerminationVetoException, uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + if ( aEvent.Source == m_xInstance && ( m_nMode & embed::Actions::PREVENT_TERMINATION ) ) + { + try + { + uno::Reference< embed::XActionsApproval > xApprove = m_xApproval; + + // unlock the mutex here + aGuard.clear(); + + if ( xApprove.is() && xApprove->approveAction( embed::Actions::PREVENT_TERMINATION ) ) + throw frame::TerminationVetoException(); + } + catch( frame::TerminationVetoException& ) + { + // rethrow this exception + throw; + } + catch( uno::Exception& ) + { + // no action should be done + } + } +} + +// -------------------------------------------------------- +void SAL_CALL OLockListener::notifyTermination( const lang::EventObject& aEvent ) + throw (uno::RuntimeException) +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + // object is terminated, no reason to listen + if ( aEvent.Source == m_xInstance ) + { + uno::Reference< frame::XDesktop > xDesktop( aEvent.Source, uno::UNO_QUERY ); + if ( xDesktop.is() ) + { + try + { + xDesktop->removeTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + m_nMode &= ~embed::Actions::PREVENT_TERMINATION; + if ( !m_nMode ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + } + } + catch( uno::Exception& ) + {} + } + } +} + + +// XInitialization +// -------------------------------------------------------- +sal_Bool OLockListener::Init() +{ + ::osl::ResettableMutexGuard aGuard( m_aMutex ); + + if ( m_bDisposed || m_bInitialized ) + return sal_False; + + try + { + if ( m_nMode & embed::Actions::PREVENT_CLOSE ) + { + uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster( m_xInstance, uno::UNO_QUERY_THROW ); + xCloseBroadcaster->addCloseListener( static_cast< util::XCloseListener* >( this ) ); + } + + if ( m_nMode & embed::Actions::PREVENT_TERMINATION ) + { + uno::Reference< frame::XDesktop > xDesktop( m_xInstance, uno::UNO_QUERY_THROW ); + xDesktop->addTerminateListener( static_cast< frame::XTerminateListener* >( this ) ); + } + } + catch( uno::Exception& ) + { + // dispose the wrapper; + uno::Reference< lang::XComponent > xComponent( m_xWrapper.get(), uno::UNO_QUERY ); + aGuard.clear(); + if ( xComponent.is() ) + { + try { xComponent->dispose(); } + catch( uno::Exception& ){} + } + + throw; + } + + m_bInitialized = sal_True; + + return sal_True; +} + -- cgit