summaryrefslogtreecommitdiff
path: root/chart2/source/tools/LifeTime.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/tools/LifeTime.cxx')
-rw-r--r--chart2/source/tools/LifeTime.cxx546
1 files changed, 546 insertions, 0 deletions
diff --git a/chart2/source/tools/LifeTime.cxx b/chart2/source/tools/LifeTime.cxx
new file mode 100644
index 000000000000..444e894a101d
--- /dev/null
+++ b/chart2/source/tools/LifeTime.cxx
@@ -0,0 +1,546 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org 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 version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+#include "LifeTime.hxx"
+#include "macros.hxx"
+#include <osl/diagnose.h>
+
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <com/sun/star/util/XCloseListener.hpp>
+
+using namespace ::com::sun::star;
+
+namespace apphelper
+{
+//--------------------------
+
+LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent, sal_Bool bLongLastingCallsCancelable )
+ : m_aListenerContainer( m_aAccessMutex )
+ , m_pComponent(pComponent)
+ , m_bLongLastingCallsCancelable(bLongLastingCallsCancelable)
+{
+ impl_init();
+}
+
+void LifeTimeManager::impl_init()
+{
+ m_bDisposed = sal_False;
+ m_bInDispose = sal_False;
+ m_nAccessCount = 0;
+ m_nLongLastingCallCount = 0;
+ m_aNoAccessCountCondition.set();
+ m_aNoLongLastingCallCountCondition.set();
+}
+
+LifeTimeManager::~LifeTimeManager()
+{
+}
+
+bool LifeTimeManager::impl_isDisposed( bool bAssert )
+{
+ if( m_bDisposed || m_bInDispose )
+ {
+ if( bAssert )
+ {
+ OSL_ENSURE( sal_False, "This component is already disposed " );
+ (void)(bAssert);
+ }
+ return sal_True;
+ }
+ return sal_False;
+}
+ sal_Bool LifeTimeManager
+::impl_canStartApiCall()
+{
+ if( impl_isDisposed() )
+ return sal_False; //behave passive if already disposed
+
+ //mutex is acquired
+ return sal_True;
+}
+
+ void LifeTimeManager
+::impl_registerApiCall(sal_Bool bLongLastingCall)
+{
+ //only allowed if not disposed
+ //do not acquire the mutex here because it will be acquired already
+ m_nAccessCount++;
+ if(m_nAccessCount==1)
+ //@todo? is it ok to wake some threads here while we have acquired the mutex?
+ m_aNoAccessCountCondition.reset();
+
+ if(bLongLastingCall)
+ m_nLongLastingCallCount++;
+ if(m_nLongLastingCallCount==1)
+ m_aNoLongLastingCallCountCondition.reset();
+}
+ void LifeTimeManager
+::impl_unregisterApiCall(sal_Bool bLongLastingCall)
+{
+ //Mutex needs to be acquired exactly ones
+ //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
+
+ OSL_ENSURE( m_nAccessCount>0, "access count mismatch" );
+ m_nAccessCount--;
+ if(bLongLastingCall)
+ m_nLongLastingCallCount--;
+ if( m_nLongLastingCallCount==0 )
+ {
+ m_aNoLongLastingCallCountCondition.set();
+ }
+ if( m_nAccessCount== 0)
+ {
+ m_aNoAccessCountCondition.set();
+ impl_apiCallCountReachedNull();
+
+ }
+}
+
+ sal_Bool LifeTimeManager
+::dispose() throw(uno::RuntimeException)
+{
+ //hold no mutex
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
+
+ if( m_bDisposed || m_bInDispose )
+ {
+ OSL_TRACE( "This component is already disposed " );
+ return sal_False; //behave passive if already disposed
+ }
+
+ m_bInDispose = true;
+ //adding any listener is not allowed anymore
+ //new calls will not be accepted
+ //still running calls have the freedom to finish their work without crash
+ }
+ //no mutex is acquired
+
+ //--do the disposing of listeners after calling this method
+ {
+ uno::Reference< lang::XComponent > xComponent =
+ uno::Reference< lang::XComponent >(m_pComponent);;
+ if(xComponent.is())
+ {
+ // notify XCLoseListeners
+ lang::EventObject aEvent( xComponent );
+ m_aListenerContainer.disposeAndClear( aEvent );
+ }
+ }
+
+ //no mutex is acquired
+ {
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aAccessMutex );
+ OSL_ENSURE( !m_bDisposed, "dispose was called already" );
+ m_bDisposed = sal_True;
+ aGuard.clear();
+ }
+ //no mutex is acquired
+
+ //wait until all still running calls have finished
+ //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed
+ m_aNoAccessCountCondition.wait();
+
+ //we are the only ones working on our data now
+
+ return sal_True;
+ //--release all resources and references after calling this method successful
+}
+
+//-----------------------------------------------------------------
+
+CloseableLifeTimeManager::CloseableLifeTimeManager( ::com::sun::star::util::XCloseable* pCloseable
+ , ::com::sun::star::lang::XComponent* pComponent
+ , sal_Bool bLongLastingCallsCancelable )
+ : LifeTimeManager( pComponent, bLongLastingCallsCancelable )
+ , m_pCloseable(pCloseable)
+{
+ impl_init();
+}
+
+CloseableLifeTimeManager::~CloseableLifeTimeManager()
+{
+}
+
+bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert )
+{
+ if( impl_isDisposed( bAssert ) )
+ return sal_True;
+
+ if( m_bClosed )
+ {
+ if( bAssert )
+ {
+ OSL_ENSURE( sal_False, "This object is already closed" );
+ (void)(bAssert);//avoid warnings
+ }
+ return sal_True;
+ }
+ return sal_False;
+}
+
+ sal_Bool CloseableLifeTimeManager
+::g_close_startTryClose(sal_Bool bDeliverOwnership)
+ throw ( uno::Exception )
+{
+ //no mutex is allowed to be acquired
+ {
+ osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
+ if( impl_isDisposedOrClosed(false) )
+ return sal_False;
+
+ //Mutex needs to be acquired exactly ones; will be released inbetween
+ if( !impl_canStartApiCall() )
+ return sal_False;
+ //mutex is acquired
+
+ //not closed already -> we try to close again
+ m_bInTryClose = sal_True;
+ m_aEndTryClosingCondition.reset();
+
+ impl_registerApiCall(sal_False);
+ }
+
+ //------------------------------------------------
+ //no mutex is acquired
+
+ //only remove listener calls will be worked on until end of tryclose
+ //all other new calls will wait till end of try close // @todo? is that really ok
+
+ //?? still running calls have the freedom to finish their work without crash
+
+ try
+ {
+ uno::Reference< util::XCloseable > xCloseable =
+ uno::Reference< util::XCloseable >(m_pCloseable);;
+ if(xCloseable.is())
+ {
+ //--call queryClosing on all registered close listeners
+ ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
+ ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
+ if( pIC )
+ {
+ //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
+ lang::EventObject aEvent( xCloseable );
+ ::cppu::OInterfaceIteratorHelper aIt( *pIC );
+ while( aIt.hasMoreElements() )
+ {
+ uno::Reference< util::XCloseListener > xCloseListener( aIt.next(), uno::UNO_QUERY );
+ if(xCloseListener.is())
+ xCloseListener->queryClosing( aEvent, bDeliverOwnership );
+ }
+ }
+ }
+ }
+ catch( uno::Exception& ex )
+ {
+ //no mutex is acquired
+ g_close_endTryClose(bDeliverOwnership, sal_False);
+ (void)(ex);
+ throw;
+ }
+ return sal_True;
+}
+
+ void CloseableLifeTimeManager
+::g_close_endTryClose(sal_Bool bDeliverOwnership, sal_Bool /* bMyVeto */ )
+{
+ //this method is called, if the try to close was not successfull
+ osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
+ impl_setOwnership( bDeliverOwnership, sal_False );
+
+ m_bInTryClose = sal_False;
+ m_aEndTryClosingCondition.set();
+
+ //Mutex needs to be acquired exactly ones
+ //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
+ impl_unregisterApiCall(sal_False);
+}
+
+ sal_Bool CloseableLifeTimeManager
+::g_close_isNeedToCancelLongLastingCalls( sal_Bool bDeliverOwnership, util::CloseVetoException& ex )
+ throw ( util::CloseVetoException )
+{
+ //this method is called when no closelistener has had a veto during queryclosing
+ //the method returns false, if nothing stands against closing anymore
+ //it returns true, if some longlasting calls are running, which might be cancelled
+ //it throws the given exception, if long calls are running but not cancelable
+
+ osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
+ //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing
+ if( !m_nLongLastingCallCount )
+ return sal_False;
+
+ if(m_bLongLastingCallsCancelable)
+ return sal_True;
+
+ impl_setOwnership( bDeliverOwnership, sal_True );
+
+ m_bInTryClose = sal_False;
+ m_aEndTryClosingCondition.set();
+
+ //Mutex needs to be acquired exactly ones
+ //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
+ impl_unregisterApiCall(sal_False);
+
+ throw ex;
+}
+
+ void CloseableLifeTimeManager
+::g_close_endTryClose_doClose()
+{
+ //this method is called, if the try to close was successfull
+ osl::ResettableGuard< osl::Mutex > aGuard( m_aAccessMutex );
+
+ m_bInTryClose = sal_False;
+ m_aEndTryClosingCondition.set();
+
+ //Mutex needs to be acquired exactly ones
+ //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
+ impl_unregisterApiCall(sal_False);
+ impl_doClose();
+}
+
+ void CloseableLifeTimeManager
+::impl_setOwnership( sal_Bool bDeliverOwnership, sal_Bool bMyVeto )
+{
+ m_bOwnership = bDeliverOwnership && bMyVeto;
+ m_bOwnershipIsWellKnown = sal_True;
+}
+ sal_Bool CloseableLifeTimeManager
+::impl_shouldCloseAtNextChance()
+{
+ return m_bOwnership;
+}
+
+ void CloseableLifeTimeManager
+::impl_apiCallCountReachedNull()
+{
+ //Mutex needs to be acquired exactly ones
+ //mutex will be released inbetween in impl_doClose()
+ if( m_pCloseable && impl_shouldCloseAtNextChance() )
+ impl_doClose();
+}
+
+ void CloseableLifeTimeManager
+::impl_doClose()
+{
+ //Mutex needs to be acquired exactly ones before calling impl_doClose()
+
+ if(m_bClosed)
+ return; //behave as passive as possible, if disposed or closed already
+ if( m_bDisposed || m_bInDispose )
+ return; //behave as passive as possible, if disposed or closed already
+
+ //--------
+ m_bClosed = sal_True;
+
+ NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex );
+ //mutex is not acquired, mutex will be reacquired at the end of this method automatically
+
+ uno::Reference< util::XCloseable > xCloseable=NULL;
+ try
+ {
+ xCloseable = uno::Reference< util::XCloseable >(m_pCloseable);;
+ if(xCloseable.is())
+ {
+ //--call notifyClosing on all registered close listeners
+ ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer.getContainer(
+ ::getCppuType((const uno::Reference< util::XCloseListener >*)0) );;
+ if( pIC )
+ {
+ //lang::EventObject aEvent( static_cast< util::XCloseable*>(xCloseable) );
+ lang::EventObject aEvent( xCloseable );
+ ::cppu::OInterfaceIteratorHelper aIt( *pIC );
+ while( aIt.hasMoreElements() )
+ {
+ uno::Reference< util::XCloseListener > xListener( aIt.next(), uno::UNO_QUERY );
+ if( xListener.is() )
+ xListener->notifyClosing( aEvent );
+ }
+ }
+ }
+ }
+ catch( uno::Exception& ex )
+ {
+ ASSERT_EXCEPTION( ex );
+ }
+
+ if(xCloseable.is())
+ {
+ uno::Reference< lang::XComponent > xComponent =
+ uno::Reference< lang::XComponent >( xCloseable, uno::UNO_QUERY );
+ if(xComponent.is())
+ {
+ OSL_ENSURE( m_bClosed, "a not closed component will be disposed " );
+ xComponent->dispose();
+ }
+ }
+ //mutex will be reacquired in destructor of aNegativeGuard
+}
+
+ sal_Bool CloseableLifeTimeManager
+::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener )
+ throw(uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard( m_aAccessMutex );
+ //Mutex needs to be acquired exactly ones; will be released inbetween
+ if( !impl_canStartApiCall() )
+ return sal_False;
+ //mutex is acquired
+
+ m_aListenerContainer.addInterface( ::getCppuType((const uno::Reference< util::XCloseListener >*)0),xListener );
+ m_bOwnership = sal_False;
+ return sal_True;
+}
+
+ sal_Bool CloseableLifeTimeManager
+::impl_canStartApiCall()
+{
+ //Mutex needs to be acquired exactly ones before calling this method
+ //the mutex will be released inbetween and reacquired
+
+ if( impl_isDisposed() )
+ return sal_False; //behave passive if already disposed
+ if( m_bClosed )
+ return sal_False; //behave passive if closing is already done
+
+ //during try-close most calls need to wait for the decision
+ while( m_bInTryClose )
+ {
+ //if someone tries to close this object at the moment
+ //we need to wait for his end because the result of the preceding call
+ //is relevant for our behaviour here
+
+ m_aAccessMutex.release();
+ m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing
+ m_aAccessMutex.acquire();
+ if( m_bDisposed || m_bInDispose || m_bClosed )
+ return sal_False; //return if closed already
+ }
+ //mutex is acquired
+ return sal_True;
+}
+
+//--------------------------
+
+ sal_Bool LifeTimeGuard
+::startApiCall(sal_Bool bLongLastingCall)
+{
+ //Mutex needs to be acquired exactly ones; will be released inbetween
+ //mutex is requiered due to constructor of LifeTimeGuard
+
+ OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" );
+ if(m_bCallRegistered)
+ return sal_False;
+
+ //Mutex needs to be acquired exactly ones; will be released inbetween
+ if( !m_rManager.impl_canStartApiCall() )
+ return sal_False;
+ //mutex is acquired
+
+ m_bCallRegistered = sal_True;
+ m_bLongLastingCallRegistered = bLongLastingCall;
+ m_rManager.impl_registerApiCall(bLongLastingCall);
+ return sal_True;
+}
+
+LifeTimeGuard::~LifeTimeGuard()
+{
+ try
+ {
+ //do acquire the mutex if it was cleared before
+ osl::MutexGuard g(m_rManager.m_aAccessMutex);
+ if(m_bCallRegistered)
+ {
+ //Mutex needs to be acquired exactly ones
+ //mutex may be released inbetween in special case of impl_apiCallCountReachedNull()
+ m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered);
+ }
+ }
+ catch( uno::Exception& ex )
+ {
+ //@todo ? allow a uno::RuntimeException from dispose to travel through??
+ ex.Context.is(); //to avoid compilation warnings
+ }
+}
+
+/*
+the XCloseable::close method has to be implemented in the following way:
+::close
+{
+ //hold no mutex
+
+ if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) )
+ return;
+ //no mutex is acquired
+
+ // At the end of this method may we must dispose ourself ...
+ // and may nobody from outside hold a reference to us ...
+ // then it's a good idea to do that by ourself.
+ uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) );
+
+ //the listeners have had no veto
+ //check wether we self can close
+ {
+ util::CloseVetoException aVetoException = util::CloseVetoException(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "the model itself could not be closed" ) )
+ , static_cast< ::cppu::OWeakObject* >(this));
+
+ if( m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ) )
+ {
+ ////you can empty this block, if you never start longlasting calls or
+ ////if your longlasting calls are per default not cancelable (check how you have constructed your LifeTimeManager)
+
+ sal_Bool bLongLastingCallsAreCanceled = sal_False;
+ try
+ {
+ //try to cancel running longlasting calls
+ //// @todo
+ }
+ catch( uno::Exception& ex )
+ {
+ //// @todo
+ //do not throw anything here!! (without endTryClose)
+ }
+ //if not successful canceled
+ if(!bLongLastingCallsAreCanceled)
+ {
+ m_aLifeTimeManager.g_close_endTryClose( bDeliverOwnership, sal_True );
+ throw aVetoException;
+ }
+ }
+
+ }
+ m_aLifeTimeManager.g_close_endTryClose_doClose();
+}
+*/
+
+}//end namespace apphelper