diff options
Diffstat (limited to 'ucb/source/cacher/cachedcontentresultsetstub.cxx')
-rw-r--r-- | ucb/source/cacher/cachedcontentresultsetstub.cxx | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/ucb/source/cacher/cachedcontentresultsetstub.cxx b/ucb/source/cacher/cachedcontentresultsetstub.cxx new file mode 100644 index 000000000..a84d8f98f --- /dev/null +++ b/ucb/source/cacher/cachedcontentresultsetstub.cxx @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "cachedcontentresultsetstub.hxx" +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/FetchError.hpp> +#include <osl/diagnose.h> +#include <cppuhelper/queryinterface.hxx> +#include <ucbhelper/macros.hxx> + +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace cppu; + + +CachedContentResultSetStub::CachedContentResultSetStub( Reference< XResultSet > const & xOrigin ) + : ContentResultSetWrapper( xOrigin ) + , m_nColumnCount( 0 ) + , m_bColumnCountCached( false ) + , m_bNeedToPropagateFetchSize( true ) + , m_bFirstFetchSizePropagationDone( false ) + , m_nLastFetchSize( 1 )//this value is not important at all + , m_bLastFetchDirection( true )//this value is not important at all + , m_aPropertyNameForFetchSize( OUString("FetchSize") ) + , m_aPropertyNameForFetchDirection( OUString("FetchDirection") ) +{ + impl_init(); +} + +CachedContentResultSetStub::~CachedContentResultSetStub() +{ + impl_deinit(); +} + + +// XInterface methods. +void SAL_CALL CachedContentResultSetStub::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL CachedContentResultSetStub::release() + noexcept +{ + OWeakObject::release(); +} + +Any SAL_CALL CachedContentResultSetStub + ::queryInterface( const Type& rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + + Any aRet = ContentResultSetWrapper::queryInterface( rType ); + if( aRet.hasValue() ) + return aRet; + + aRet = cppu::queryInterface( rType + , static_cast< XTypeProvider* >( this ) + , static_cast< XServiceInfo* >( this ) + , static_cast< XFetchProvider* >( this ) + , static_cast< XFetchProviderForContentAccess* >( this ) + ); + + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +// own methods. ( inherited ) + + +//virtual +void CachedContentResultSetStub + ::impl_propertyChange( const PropertyChangeEvent& rEvt ) +{ + impl_EnsureNotDisposed(); + + //don't notify events on fetchsize and fetchdirection to the above CachedContentResultSet + //because it will ignore them anyway and we can save this remote calls + if( rEvt.PropertyName == m_aPropertyNameForFetchSize + || rEvt.PropertyName == m_aPropertyNameForFetchDirection ) + return; + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + + impl_notifyPropertyChangeListeners( aEvt ); +} + + +//virtual +void CachedContentResultSetStub + ::impl_vetoableChange( const PropertyChangeEvent& rEvt ) +{ + impl_EnsureNotDisposed(); + + //don't notify events on fetchsize and fetchdirection to the above CachedContentResultSet + //because it will ignore them anyway and we can save this remote calls + if( rEvt.PropertyName == m_aPropertyNameForFetchSize + || rEvt.PropertyName == m_aPropertyNameForFetchDirection ) + return; + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + + impl_notifyVetoableChangeListeners( aEvt ); +} + + +// XTypeProvider methods. + + +XTYPEPROVIDER_COMMON_IMPL( CachedContentResultSetStub ) +//list all interfaces exclusive baseclasses +Sequence< Type > SAL_CALL CachedContentResultSetStub + ::getTypes() +{ + static Sequence<Type> ourTypes( + { CPPU_TYPE_REF( XTypeProvider ), + CPPU_TYPE_REF( XServiceInfo ), + CPPU_TYPE_REF( XComponent ), + CPPU_TYPE_REF( XCloseable ), + CPPU_TYPE_REF( XResultSetMetaDataSupplier ), + CPPU_TYPE_REF( XPropertySet ), + CPPU_TYPE_REF( XPropertyChangeListener ), + CPPU_TYPE_REF( XVetoableChangeListener ), + CPPU_TYPE_REF( XResultSet ), + CPPU_TYPE_REF( XContentAccess ), + CPPU_TYPE_REF( XRow ), + CPPU_TYPE_REF( XFetchProvider ), + CPPU_TYPE_REF( XFetchProviderForContentAccess ) } ); + + return ourTypes; +} + + +// XServiceInfo methods. + +OUString SAL_CALL CachedContentResultSetStub::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedContentResultSetStub"; +} + +sal_Bool SAL_CALL CachedContentResultSetStub::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetStub::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedContentResultSetStub" }; +} + + + +// XFetchProvider methods. + + +FetchResult CachedContentResultSetStub::impl_fetchHelper( + sal_Int32 nRowStartPosition, sal_Int32 nRowCount, bool bDirection, + std::function<void( css::uno::Any& rRowContent)> impl_loadRow) +{ + impl_EnsureNotDisposed(); + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + impl_propagateFetchSizeAndDirection( nRowCount, bDirection ); + FetchResult aRet; + aRet.StartIndex = nRowStartPosition; + aRet.Orientation = bDirection; + aRet.FetchError = FetchError::SUCCESS; /*ENDOFDATA, EXCEPTION*/ + sal_Int32 nOldOriginal_Pos = m_xResultSetOrigin->getRow(); + if( impl_isForwardOnly() ) + { + if( nOldOriginal_Pos != nRowStartPosition ) + { + /*@todo*/ + aRet.FetchError = FetchError::EXCEPTION; + return aRet; + } + if( nRowCount != 1 ) + aRet.FetchError = FetchError::EXCEPTION; + + aRet.Rows.realloc( 1 ); + + try + { + impl_loadRow( aRet.Rows.getArray()[0] ); + } + catch( SQLException& ) + { + aRet.Rows.realloc( 0 ); + aRet.FetchError = FetchError::EXCEPTION; + return aRet; + } + return aRet; + } + aRet.Rows.realloc( nRowCount ); + auto pRows = aRet.Rows.getArray(); + bool bOldOriginal_AfterLast = false; + if( !nOldOriginal_Pos ) + bOldOriginal_AfterLast = m_xResultSetOrigin->isAfterLast(); + sal_Int32 nN = 1; + try + { + bool bValidNewPos = false; + try + { + /*if( nOldOriginal_Pos != nRowStartPosition )*/ + bValidNewPos = m_xResultSetOrigin->absolute( nRowStartPosition ); + } + catch( SQLException& ) + { + aRet.Rows.realloc( 0 ); + aRet.FetchError = FetchError::EXCEPTION; + return aRet; + } + if( !bValidNewPos ) + { + aRet.Rows.realloc( 0 ); + aRet.FetchError = FetchError::EXCEPTION; + + /*restore old position*/ + if( nOldOriginal_Pos ) + m_xResultSetOrigin->absolute( nOldOriginal_Pos ); + else if( bOldOriginal_AfterLast ) + m_xResultSetOrigin->afterLast(); + else + m_xResultSetOrigin->beforeFirst(); + + return aRet; + } + for( ; nN <= nRowCount; ) + { + impl_loadRow( pRows[nN-1] ); + nN++; + if( nN <= nRowCount ) + { + if( bDirection ) + { + if( !m_xResultSetOrigin->next() ) + { + aRet.Rows.realloc( nN-1 ); + aRet.FetchError = FetchError::ENDOFDATA; + break; + } + } + else + { + if( !m_xResultSetOrigin->previous() ) + { + aRet.Rows.realloc( nN-1 ); + aRet.FetchError = FetchError::ENDOFDATA; + break; + } + } + } + } + } + catch( SQLException& ) + { + aRet.Rows.realloc( nN-1 ); + aRet.FetchError = FetchError::EXCEPTION; + } + /*restore old position*/ + if( nOldOriginal_Pos ) + m_xResultSetOrigin->absolute( nOldOriginal_Pos ); + else if( bOldOriginal_AfterLast ) + m_xResultSetOrigin->afterLast(); + else + m_xResultSetOrigin->beforeFirst(); + return aRet; +} + +FetchResult SAL_CALL CachedContentResultSetStub + ::fetch( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + impl_init_xRowOrigin(); + return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection, + [&](css::uno::Any& rRowContent) + { return impl_getCurrentRowContent(rRowContent, m_xRowOrigin); }); +} + +sal_Int32 CachedContentResultSetStub + ::impl_getColumnCount() +{ + sal_Int32 nCount; + bool bCached; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + nCount = m_nColumnCount; + bCached = m_bColumnCountCached; + } + if( !bCached ) + { + try + { + Reference< XResultSetMetaData > xMetaData = getMetaData(); + if( xMetaData.is() ) + nCount = xMetaData->getColumnCount(); + } + catch( SQLException& ) + { + OSL_FAIL( "couldn't determine the column count" ); + nCount = 0; + } + } + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_nColumnCount = nCount; + m_bColumnCountCached = true; + return m_nColumnCount; +} + +void CachedContentResultSetStub + ::impl_getCurrentRowContent( Any& rRowContent + , const Reference< XRow >& xRow ) +{ + sal_Int32 nCount = impl_getColumnCount(); + + Sequence< Any > aContent( nCount ); + auto aContentRange = asNonConstRange(aContent); + for( sal_Int32 nN = 1; nN <= nCount; nN++ ) + { + aContentRange[nN-1] = xRow->getObject( nN, nullptr ); + } + + rRowContent <<= aContent; +} + +void CachedContentResultSetStub + ::impl_propagateFetchSizeAndDirection( sal_Int32 nFetchSize, bool bFetchDirection ) +{ + //this is done only for the case, that there is another CachedContentResultSet in the chain of underlying ResultSets + + //we do not propagate the property 'FetchSize' or 'FetchDirection' via 'setPropertyValue' from the above CachedContentResultSet to save remote calls + + //if the underlying ResultSet has a property FetchSize and FetchDirection, + //we will set these properties, if the new given parameters are different from the last ones + + if( !m_bNeedToPropagateFetchSize ) + return; + + bool bNeedAction; + sal_Int32 nLastSize; + bool bLastDirection; + bool bFirstPropagationDone; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + bNeedAction = m_bNeedToPropagateFetchSize; + nLastSize = m_nLastFetchSize; + bLastDirection = m_bLastFetchDirection; + bFirstPropagationDone = m_bFirstFetchSizePropagationDone; + } + if( !bNeedAction ) + return; + + if( nLastSize == nFetchSize + && bLastDirection == bFetchDirection + && bFirstPropagationDone ) + return; + + if(!bFirstPropagationDone) + { + //check whether the properties 'FetchSize' and 'FetchDirection' do exist + + Reference< XPropertySetInfo > xPropertySetInfo = getPropertySetInfo(); + bool bHasSize = xPropertySetInfo->hasPropertyByName( m_aPropertyNameForFetchSize ); + bool bHasDirection = xPropertySetInfo->hasPropertyByName( m_aPropertyNameForFetchDirection ); + + if(!bHasSize || !bHasDirection) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_bNeedToPropagateFetchSize = false; + return; + } + } + + bool bSetSize = ( nLastSize !=nFetchSize ) || !bFirstPropagationDone; + bool bSetDirection = ( bLastDirection !=bFetchDirection ) || !bFirstPropagationDone; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_bFirstFetchSizePropagationDone = true; + m_nLastFetchSize = nFetchSize; + m_bLastFetchDirection = bFetchDirection; + } + + if( bSetSize ) + { + Any aValue; + aValue <<= nFetchSize; + try + { + setPropertyValue( m_aPropertyNameForFetchSize, aValue ); + } + catch( css::uno::Exception& ) {} + } + if( !bSetDirection ) + return; + + sal_Int32 nFetchDirection = FetchDirection::FORWARD; + if( !bFetchDirection ) + nFetchDirection = FetchDirection::REVERSE; + Any aValue; + aValue <<= nFetchDirection; + try + { + setPropertyValue( m_aPropertyNameForFetchDirection, aValue ); + } + catch( css::uno::Exception& ) {} +} + + +// XFetchProviderForContentAccess methods. + + +void CachedContentResultSetStub + ::impl_getCurrentContentIdentifierString( Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContentIdentifierString(); +} + +void CachedContentResultSetStub + ::impl_getCurrentContentIdentifier( Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContentIdentifier(); +} + +void CachedContentResultSetStub + ::impl_getCurrentContent( Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContent(); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContentIdentifierStrings( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + impl_init_xContentAccessOrigin(); + return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection, + [&](css::uno::Any& rRowContent) + { return impl_getCurrentContentIdentifierString(rRowContent, m_xContentAccessOrigin); }); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContentIdentifiers( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + impl_init_xContentAccessOrigin(); + return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection, + [&](css::uno::Any& rRowContent) + { return impl_getCurrentContentIdentifier(rRowContent, m_xContentAccessOrigin); }); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContents( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + impl_init_xContentAccessOrigin(); + return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection, + [&](css::uno::Any& rRowContent) + { return impl_getCurrentContent(rRowContent, m_xContentAccessOrigin); }); +} + + + + +CachedContentResultSetStubFactory::CachedContentResultSetStubFactory() +{ +} + +CachedContentResultSetStubFactory::~CachedContentResultSetStubFactory() +{ +} + + +// CachedContentResultSetStubFactory XServiceInfo methods. + +OUString SAL_CALL CachedContentResultSetStubFactory::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedContentResultSetStubFactory"; +} +sal_Bool SAL_CALL CachedContentResultSetStubFactory::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} +css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetStubFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedContentResultSetStubFactory" }; +} + +// Service factory implementation. + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_CachedContentResultSetStubFactory_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new CachedContentResultSetStubFactory()); +} + + + + +// CachedContentResultSetStubFactory XCachedContentResultSetStubFactory methods. + + + //virtual +Reference< XResultSet > SAL_CALL CachedContentResultSetStubFactory + ::createCachedContentResultSetStub( + const Reference< XResultSet > & xSource ) +{ + if( xSource.is() ) + { + Reference< XResultSet > xRet = new CachedContentResultSetStub( xSource ); + return xRet; + } + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |