diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /ucb/source/cacher | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/cacher')
-rw-r--r-- | ucb/source/cacher/cached1.component | 38 | ||||
-rw-r--r-- | ucb/source/cacher/cachedcontentresultset.cxx | 2037 | ||||
-rw-r--r-- | ucb/source/cacher/cachedcontentresultset.hxx | 386 | ||||
-rw-r--r-- | ucb/source/cacher/cachedcontentresultsetstub.cxx | 551 | ||||
-rw-r--r-- | ucb/source/cacher/cachedcontentresultsetstub.hxx | 168 | ||||
-rw-r--r-- | ucb/source/cacher/cacheddynamicresultset.cxx | 200 | ||||
-rw-r--r-- | ucb/source/cacher/cacheddynamicresultset.hxx | 104 | ||||
-rw-r--r-- | ucb/source/cacher/cacheddynamicresultsetstub.cxx | 235 | ||||
-rw-r--r-- | ucb/source/cacher/cacheddynamicresultsetstub.hxx | 101 | ||||
-rw-r--r-- | ucb/source/cacher/contentresultsetwrapper.cxx | 1207 | ||||
-rw-r--r-- | ucb/source/cacher/contentresultsetwrapper.hxx | 384 | ||||
-rw-r--r-- | ucb/source/cacher/dynamicresultsetwrapper.cxx | 478 | ||||
-rw-r--r-- | ucb/source/cacher/dynamicresultsetwrapper.hxx | 182 |
13 files changed, 6071 insertions, 0 deletions
diff --git a/ucb/source/cacher/cached1.component b/ucb/source/cacher/cached1.component new file mode 100644 index 0000000000..ff460c510c --- /dev/null +++ b/ucb/source/cacher/cached1.component @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.ucb.CachedContentResultSetFactory" + constructor="ucb_CachedContentResultSetFactory_get_implementation"> + <service name="com.sun.star.ucb.CachedContentResultSetFactory"/> + </implementation> + <implementation name="com.sun.star.comp.ucb.CachedContentResultSetStubFactory" + constructor="ucb_CachedContentResultSetStubFactory_get_implementation"> + <service name="com.sun.star.ucb.CachedContentResultSetStubFactory"/> + </implementation> + <implementation name="com.sun.star.comp.ucb.CachedDynamicResultSetFactory" + constructor="ucb_CachedDynamicResultSetFactory_get_implementation"> + <service name="com.sun.star.ucb.CachedDynamicResultSetFactory"/> + </implementation> + <implementation name="com.sun.star.comp.ucb.CachedDynamicResultSetStubFactory" + constructor="ucb_CachedDynamicResultSetStubFactory_get_implementation"> + <service name="com.sun.star.ucb.CachedDynamicResultSetStubFactory"/> + </implementation> +</component> diff --git a/ucb/source/cacher/cachedcontentresultset.cxx b/ucb/source/cacher/cachedcontentresultset.cxx new file mode 100644 index 0000000000..769c162fd2 --- /dev/null +++ b/ucb/source/cacher/cachedcontentresultset.cxx @@ -0,0 +1,2037 @@ +/* -*- 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 "cachedcontentresultset.hxx" +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/FetchError.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/script/Converter.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <rtl/ustring.hxx> +#include <o3tl/any.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <ucbhelper/macros.hxx> +#include <optional> +#include <string_view> + +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::script; +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; + + +#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE 256 +#define COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION FetchDirection::FORWARD + +//if you change this function template please pay attention to +//function getObject, where this is similar implemented + +template<typename T> T CachedContentResultSet::rowOriginGet( + T (SAL_CALL css::sdbc::XRow::* f)(sal_Int32), sal_Int32 columnIndex) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + sal_Int32 nRow = m_nRow; + sal_Int32 nFetchSize = m_nFetchSize; + sal_Int32 nFetchDirection = m_nFetchDirection; + if( !m_aCache.hasRow( nRow ) ) + { + if( !m_aCache.hasCausedException( nRow ) ) + { + if( !m_xFetchProvider.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw SQLException(); + } + if( impl_isForwardOnly(aGuard) ) + applyPositionToOrigin( aGuard, nRow ); + + impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection ); + } + if( !m_aCache.hasRow( nRow ) ) + { + m_bLastReadWasFromCache = false; + applyPositionToOrigin( aGuard, nRow ); + impl_init_xRowOrigin(aGuard); + aGuard.unlock(); + return (m_xRowOrigin.get()->*f)( columnIndex ); + } + } + const Any& rValue = m_aCache.getAny( nRow, columnIndex ); + T aRet = T(); + m_bLastReadWasFromCache = true; + m_bLastCachedReadWasNull = !( rValue >>= aRet ); + /* Last chance. Try type converter service... */ + if ( m_bLastCachedReadWasNull && rValue.hasValue() ) + { + Reference< XTypeConverter > xConverter = getTypeConverter(aGuard); + if ( xConverter.is() ) + { + try + { + Any aConvAny = xConverter->convertTo( + rValue, + cppu::UnoType<T>::get() ); + m_bLastCachedReadWasNull = !( aConvAny >>= aRet ); + } + catch (const IllegalArgumentException&) + { + } + catch (const CannotConvertException&) + { + } + } + } + return aRet; +} + + +// CCRS_Cache methods + + +CachedContentResultSet::CCRS_Cache::CCRS_Cache( + const Reference< XContentIdentifierMapping > & xMapping ) + : m_xContentIdentifierMapping( xMapping ) +{ +} + +CachedContentResultSet::CCRS_Cache::~CCRS_Cache() +{ +} + +void CachedContentResultSet::CCRS_Cache + ::clear() +{ + m_pResult.reset(); + m_pMappedReminder.reset(); +} + +void CachedContentResultSet::CCRS_Cache + ::loadData( const FetchResult& rResult ) +{ + clear(); + m_pResult = rResult; +} + +bool CachedContentResultSet::CCRS_Cache + ::hasRow( sal_Int32 row ) const +{ + if( !m_pResult ) + return false; + sal_Int32 nStart = m_pResult->StartIndex; + sal_Int32 nEnd = nStart; + if( m_pResult->Orientation ) + nEnd += m_pResult->Rows.getLength() - 1; + else + nStart -= m_pResult->Rows.getLength() + 1; + + return nStart <= row && row <= nEnd; +} + +sal_Int32 CachedContentResultSet::CCRS_Cache + ::getMaxRow() const +{ + if( !m_pResult ) + return 0; + sal_Int32 nEnd = m_pResult->StartIndex; + if( m_pResult->Orientation ) + return nEnd + m_pResult->Rows.getLength() - 1; + else + return nEnd; +} + +bool CachedContentResultSet::CCRS_Cache + ::hasKnownLast() const +{ + if( !m_pResult ) + return false; + + return ( m_pResult->FetchError & FetchError::ENDOFDATA ) + && m_pResult->Orientation + && m_pResult->Rows.hasElements(); +} + +bool CachedContentResultSet::CCRS_Cache + ::hasCausedException( sal_Int32 nRow ) const +{ + if( !m_pResult ) + return false; + if( !( m_pResult->FetchError & FetchError::EXCEPTION ) ) + return false; + + sal_Int32 nEnd = m_pResult->StartIndex; + if( m_pResult->Orientation ) + nEnd += m_pResult->Rows.getLength(); + + return nRow == nEnd+1; +} + +Any& CachedContentResultSet::CCRS_Cache + ::getRowAny( sal_Int32 nRow ) +{ + if( !nRow ) + throw SQLException(); + if( !m_pResult ) + throw SQLException(); + if( !hasRow( nRow ) ) + throw SQLException(); + + sal_Int32 nDiff = nRow - m_pResult->StartIndex; + if( nDiff < 0 ) + nDiff *= -1; + + return m_pResult->Rows.getArray()[nDiff]; +} + +void CachedContentResultSet::CCRS_Cache + ::remindMapped( sal_Int32 nRow ) +{ + //remind that this row was mapped + if( !m_pResult ) + return; + sal_Int32 nDiff = nRow - m_pResult->StartIndex; + if( nDiff < 0 ) + nDiff *= -1; + Sequence< sal_Bool >& rMappedReminder = getMappedReminder(); + if( nDiff < rMappedReminder.getLength() ) + { + sal_Bool* pMappedReminder = rMappedReminder.getArray(); + pMappedReminder[nDiff] = true; + } +} + +bool CachedContentResultSet::CCRS_Cache + ::isRowMapped( sal_Int32 nRow ) +{ + if( !m_pMappedReminder || !m_pResult ) + return false; + sal_Int32 nDiff = nRow - m_pResult->StartIndex; + if( nDiff < 0 ) + nDiff *= -1; + if( nDiff < m_pMappedReminder->getLength() ) + return (*m_pMappedReminder)[nDiff]; + return false; +} + +Sequence< sal_Bool >& CachedContentResultSet::CCRS_Cache + ::getMappedReminder() +{ + if( !m_pMappedReminder ) + { + sal_Int32 nCount = m_pResult->Rows.getLength(); + m_pMappedReminder.emplace( nCount ); + std::fill_n(m_pMappedReminder->getArray(), m_pMappedReminder->getLength(), false); + } + return *m_pMappedReminder; +} + +const Any& CachedContentResultSet::CCRS_Cache + ::getAny( sal_Int32 nRow, sal_Int32 nColumnIndex ) +{ + if( !nColumnIndex ) + throw SQLException(); + if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) + { + Any& rRow = getRowAny( nRow ); + Sequence< Any > aValue; + rRow >>= aValue; + if( m_xContentIdentifierMapping->mapRow( aValue ) ) + { + rRow <<= aValue; + remindMapped( nRow ); + } + else + m_xContentIdentifierMapping.clear(); + } + auto & rowAny = getRowAny(nRow); + auto rRow = o3tl::doAccess<Sequence<Any>>(rowAny); + + if( nColumnIndex > rRow->getLength() ) + throw SQLException(); + return (*rRow)[nColumnIndex-1]; +} + +OUString const & CachedContentResultSet::CCRS_Cache + ::getContentIdentifierString( sal_Int32 nRow ) +{ + try + { + if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) + { + Any& rRow = getRowAny( nRow ); + OUString aValue; + rRow >>= aValue; + rRow <<= m_xContentIdentifierMapping->mapContentIdentifierString( aValue ); + remindMapped( nRow ); + } + return *o3tl::doAccess<OUString>(getRowAny(nRow)); + } + catch(const SQLException& ex) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( ex.Message, + css::uno::Reference< css::uno::XInterface >(), + anyEx ); + } +} + +Reference< XContentIdentifier > CachedContentResultSet::CCRS_Cache + ::getContentIdentifier( sal_Int32 nRow ) +{ + try + { + if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) + { + Any& rRow = getRowAny( nRow ); + Reference< XContentIdentifier > aValue; + rRow >>= aValue; + rRow <<= m_xContentIdentifierMapping->mapContentIdentifier( aValue ); + remindMapped( nRow ); + } + return *o3tl::doAccess<Reference<XContentIdentifier>>(getRowAny(nRow)); + } + catch(const SQLException& ex) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( ex.Message, + css::uno::Reference< css::uno::XInterface >(), + anyEx ); + } +} + +Reference< XContent > CachedContentResultSet::CCRS_Cache + ::getContent( sal_Int32 nRow ) +{ + try + { + if( m_xContentIdentifierMapping.is() && !isRowMapped( nRow ) ) + { + Any& rRow = getRowAny( nRow ); + Reference< XContent > aValue; + rRow >>= aValue; + rRow <<= m_xContentIdentifierMapping->mapContent( aValue ); + remindMapped( nRow ); + } + return *o3tl::doAccess<Reference<XContent>>(getRowAny(nRow)); + } + catch (const SQLException& ex) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( ex.Message, + css::uno::Reference< css::uno::XInterface >(), + anyEx ); + } +} + + + + +class CCRS_PropertySetInfo : + public cppu::OWeakObject, + public css::lang::XTypeProvider, + public css::beans::XPropertySetInfo +{ + friend class CachedContentResultSet; + + //my Properties + std::optional<Sequence< css::beans::Property >> + m_xProperties; + + sal_Int32 m_nFetchSizePropertyHandle; + sal_Int32 m_nFetchDirectionPropertyHandle; + +private: + sal_Int32 + impl_getRemainedHandle() const; + + bool + impl_queryProperty( + std::u16string_view rName + , css::beans::Property& rProp ) const; + sal_Int32 + impl_getPos( std::u16string_view rName ) const; + + static bool + impl_isMyPropertyName( std::u16string_view rName ); + +public: + explicit CCRS_PropertySetInfo( Reference< + XPropertySetInfo > const & xPropertySetInfoOrigin ); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XPropertySetInfo + virtual Sequence< css::beans::Property > SAL_CALL + getProperties() override; + + virtual css::beans::Property SAL_CALL + getPropertyByName( const OUString& aName ) override; + + virtual sal_Bool SAL_CALL + hasPropertyByName( const OUString& Name ) override; +}; + +//some helping variables ( names for my special properties ) +const char16_t g_sPropertyNameForCount[] = u"RowCount"; +const char16_t g_sPropertyNameForFinalCount[] = u"IsRowCountFinal"; +constexpr OUString g_sPropertyNameForFetchSize(u"FetchSize"_ustr); +constexpr OUString g_sPropertyNameForFetchDirection(u"FetchDirection"_ustr); + +CCRS_PropertySetInfo::CCRS_PropertySetInfo( + Reference< XPropertySetInfo > const & xInfo ) + : m_nFetchSizePropertyHandle( -1 ) + , m_nFetchDirectionPropertyHandle( -1 ) +{ + //initialize list of properties: + + // it is required, that the received xInfo contains the two + // properties with names 'g_sPropertyNameForCount' and + // 'g_sPropertyNameForFinalCount' + + if( xInfo.is() ) + { + m_xProperties = xInfo->getProperties(); + } + else + { + OSL_FAIL( "The received XPropertySetInfo doesn't contain required properties" ); + m_xProperties.emplace(); + } + + //ensure, that we haven't got the Properties 'FetchSize' and 'Direction' twice: + sal_Int32 nFetchSize = impl_getPos( g_sPropertyNameForFetchSize ); + sal_Int32 nFetchDirection = impl_getPos( g_sPropertyNameForFetchDirection ); + sal_Int32 nDeleted = 0; + if( nFetchSize != -1 ) + nDeleted++; + if( nFetchDirection != -1 ) + nDeleted++; + + Sequence< Property > aOrigProps( *m_xProperties ); + sal_Int32 nOrigProps = aOrigProps.getLength(); + + m_xProperties->realloc( nOrigProps + 2 - nDeleted );//note that nDeleted is <= 2 + auto pProperties = m_xProperties->getArray(); + for( sal_Int32 n = 0, m = 0; n < nOrigProps; n++, m++ ) + { + if( n == nFetchSize || n == nFetchDirection ) + m--; + else + pProperties[ m ] = aOrigProps[ n ]; + } + { + Property& rMyProp = pProperties[ nOrigProps - nDeleted ]; + rMyProp.Name = g_sPropertyNameForFetchSize; + rMyProp.Type = cppu::UnoType<sal_Int32>::get(); + rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT; + + if( nFetchSize != -1 ) + m_nFetchSizePropertyHandle = aOrigProps[nFetchSize].Handle; + else + m_nFetchSizePropertyHandle = impl_getRemainedHandle(); + + rMyProp.Handle = m_nFetchSizePropertyHandle; + + } + { + Property& rMyProp = pProperties[ nOrigProps - nDeleted + 1 ]; + rMyProp.Name = g_sPropertyNameForFetchDirection; + rMyProp.Type = cppu::UnoType<sal_Bool>::get(); + rMyProp.Attributes = PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT; + + m_nFetchDirectionPropertyHandle = rMyProp.Handle; + } +} + +// XInterface methods. + +void SAL_CALL CCRS_PropertySetInfo::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL CCRS_PropertySetInfo::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL CCRS_PropertySetInfo::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XTypeProvider* >(this), + static_cast< XPropertySetInfo* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XTypeProvider methods. + +//list all interfaces exclusive baseclasses +XTYPEPROVIDER_IMPL_2( CCRS_PropertySetInfo + , XTypeProvider + , XPropertySetInfo + ); + +// XPropertySetInfo methods. + +//virtual +Sequence< Property > SAL_CALL CCRS_PropertySetInfo + ::getProperties() +{ + return *m_xProperties; +} + +//virtual +Property SAL_CALL CCRS_PropertySetInfo + ::getPropertyByName( const OUString& aName ) +{ + Property aProp; + if ( impl_queryProperty( aName, aProp ) ) + return aProp; + + throw UnknownPropertyException(aName); +} + +//virtual +sal_Bool SAL_CALL CCRS_PropertySetInfo + ::hasPropertyByName( const OUString& Name ) +{ + return ( impl_getPos( Name ) != -1 ); +} + + +// impl_ methods. + + +sal_Int32 CCRS_PropertySetInfo + ::impl_getPos( std::u16string_view rName ) const +{ + for( sal_Int32 nN = m_xProperties->getLength(); nN--; ) + { + const Property& rMyProp = (*m_xProperties)[nN]; + if( rMyProp.Name == rName ) + return nN; + } + return -1; +} + +bool CCRS_PropertySetInfo + ::impl_queryProperty( std::u16string_view rName, Property& rProp ) const +{ + for( const Property& rMyProp : std::as_const(*m_xProperties) ) + { + if( rMyProp.Name == rName ) + { + rProp.Name = rMyProp.Name; + rProp.Handle = rMyProp.Handle; + rProp.Type = rMyProp.Type; + rProp.Attributes = rMyProp.Attributes; + + return true; + } + } + return false; +} + +//static +bool CCRS_PropertySetInfo + ::impl_isMyPropertyName( std::u16string_view rPropertyName ) +{ + return ( rPropertyName == g_sPropertyNameForCount + || rPropertyName == g_sPropertyNameForFinalCount + || rPropertyName == g_sPropertyNameForFetchSize + || rPropertyName == g_sPropertyNameForFetchDirection ); +} + +sal_Int32 CCRS_PropertySetInfo + ::impl_getRemainedHandle( ) const +{ + sal_Int32 nHandle = 1; + + if( !m_xProperties ) + { + OSL_FAIL( "Properties not initialized yet" ); + return nHandle; + } + bool bFound = true; + while( bFound ) + { + bFound = false; + for( const auto & rProp : std::as_const(*m_xProperties) ) + { + if( nHandle == rProp.Handle ) + { + bFound = true; + nHandle++; + break; + } + } + } + return nHandle; +} + + + + +CachedContentResultSet::CachedContentResultSet( + const Reference< XComponentContext > & rxContext + , const Reference< XResultSet > & xOrigin + , const Reference< XContentIdentifierMapping > & + xContentIdentifierMapping ) + : ContentResultSetWrapper( xOrigin ) + + , m_xContext( rxContext ) + + , m_xContentIdentifierMapping( xContentIdentifierMapping ) + , m_nRow( 0 ) // Position is one-based. Zero means: before first element. + , m_bAfterLast( false ) + , m_nLastAppliedPos( 0 ) + , m_bAfterLastApplied( false ) + , m_nKnownCount( 0 ) + , m_bFinalCount( false ) + , m_nFetchSize( + COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE ) + , m_nFetchDirection( + COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION ) + + , m_bLastReadWasFromCache( false ) + , m_bLastCachedReadWasNull( true ) + , m_aCache( m_xContentIdentifierMapping ) + , m_aCacheContentIdentifierString( m_xContentIdentifierMapping ) + , m_aCacheContentIdentifier( m_xContentIdentifierMapping ) + , m_aCacheContent( m_xContentIdentifierMapping ) + , m_bTriedToGetTypeConverter( false ) +{ + m_xFetchProvider.set( m_xResultSetOrigin, UNO_QUERY ); + OSL_ENSURE( m_xFetchProvider.is(), "interface XFetchProvider is required" ); + + m_xFetchProviderForContentAccess.set( m_xResultSetOrigin, UNO_QUERY ); + OSL_ENSURE( m_xFetchProviderForContentAccess.is(), "interface XFetchProviderForContentAccess is required" ); + + impl_init(); +}; + +CachedContentResultSet::~CachedContentResultSet() +{ + impl_deinit(); + //do not delete m_pMyPropSetInfo, cause it is hold via reference +}; + + +// impl_ methods. + + +bool CachedContentResultSet + ::applyPositionToOrigin( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow ) +{ + impl_EnsureNotDisposed(rGuard); + + /** + @returns + <TRUE/> if the cursor is on a valid row; <FALSE/> if it is off + the result set. + */ + + OSL_ENSURE( nRow >= 0, "only positive values supported" ); + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } +// OSL_ENSURE( nRow <= m_nKnownCount, "don't step into regions you don't know with this method" ); + + sal_Int32 nLastAppliedPos = m_nLastAppliedPos; + bool bAfterLastApplied = m_bAfterLastApplied; + bool bAfterLast = m_bAfterLast; + sal_Int32 nForwardOnly = m_nForwardOnly; + + rGuard.unlock(); + + if( bAfterLastApplied || nLastAppliedPos != nRow ) + { + if( nForwardOnly == 1 ) + { + if( bAfterLastApplied || bAfterLast || !nRow || nRow < nLastAppliedPos ) + throw SQLException(); + + sal_Int32 nN = nRow - nLastAppliedPos; + sal_Int32 nM; + for( nM = 0; nN--; nM++ ) + { + if( !m_xResultSetOrigin->next() ) + break; + } + + rGuard.lock(); + m_nLastAppliedPos += nM; + m_bAfterLastApplied = nRow != m_nLastAppliedPos; + return nRow == m_nLastAppliedPos; + } + + if( !nRow ) //absolute( 0 ) will throw exception + { + m_xResultSetOrigin->beforeFirst(); + + rGuard.lock(); + m_nLastAppliedPos = 0; + m_bAfterLastApplied = false; + return false; + } + try + { + //move absolute, if !nLastAppliedPos + //because move relative would throw exception + if( !nLastAppliedPos || bAfterLast || bAfterLastApplied ) + { + bool bValid = m_xResultSetOrigin->absolute( nRow ); + + rGuard.lock(); + m_nLastAppliedPos = nRow; + m_bAfterLastApplied = !bValid; + return bValid; + } + else + { + bool bValid = m_xResultSetOrigin->relative( nRow - nLastAppliedPos ); + + rGuard.lock(); + m_nLastAppliedPos += ( nRow - nLastAppliedPos ); + m_bAfterLastApplied = !bValid; + return bValid; + } + } + catch (const SQLException&) + { + rGuard.lock(); + if( !bAfterLastApplied && !bAfterLast && nRow > nLastAppliedPos && impl_isForwardOnly(rGuard) ) + { + sal_Int32 nN = nRow - nLastAppliedPos; + sal_Int32 nM; + for( nM = 0; nN--; nM++ ) + { + if( !m_xResultSetOrigin->next() ) + break; + } + + m_nLastAppliedPos += nM; + m_bAfterLastApplied = nRow != m_nLastAppliedPos; + } + else + throw; + } + + return nRow == m_nLastAppliedPos; + } + return true; +}; + + +//define for fetching data + + +#define FETCH_XXX( aCache, fetchInterface, fetchMethod ) \ +bool bDirection = !!( \ + nFetchDirection != FetchDirection::REVERSE ); \ +FetchResult aResult = \ + fetchInterface->fetchMethod( nRow, nFetchSize, bDirection ); \ +aCache.loadData( aResult ); \ +sal_Int32 nMax = aCache.getMaxRow(); \ +sal_Int32 nCurCount = m_nKnownCount; \ +bool bIsFinalCount = aCache.hasKnownLast(); \ +bool bCurIsFinalCount = m_bFinalCount; \ +if( nMax > nCurCount ) \ + impl_changeRowCount( rGuard, nCurCount, nMax ); \ +if( bIsFinalCount && !bCurIsFinalCount ) \ + impl_changeIsRowCountFinal( rGuard, bCurIsFinalCount, bIsFinalCount ); + +void CachedContentResultSet + ::impl_fetchData( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow + , sal_Int32 nFetchSize, sal_Int32 nFetchDirection ) +{ + FETCH_XXX( m_aCache, m_xFetchProvider, fetch ); +} + +void CachedContentResultSet + ::impl_changeRowCount( std::unique_lock<std::mutex>& rGuard, sal_Int32 nOld, sal_Int32 nNew ) +{ + OSL_ENSURE( nNew > nOld, "RowCount only can grow" ); + if( nNew <= nOld ) + return; + + //create PropertyChangeEvent and set value + PropertyChangeEvent aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + aEvt.OldValue <<= nOld; + aEvt.NewValue <<= nNew; + + m_nKnownCount = nNew; + + //send PropertyChangeEvent to listeners + impl_notifyPropertyChangeListeners( rGuard, aEvt ); +} + +void CachedContentResultSet + ::impl_changeIsRowCountFinal( std::unique_lock<std::mutex>& rGuard, bool bOld, bool bNew ) +{ + OSL_ENSURE( !bOld && bNew, "This change is not allowed for IsRowCountFinal" ); + if( bOld || !bNew ) + return; + + //create PropertyChangeEvent and set value + PropertyChangeEvent aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + aEvt.OldValue <<= bOld; + aEvt.NewValue <<= bNew; + + m_bFinalCount = bNew; + + //send PropertyChangeEvent to listeners + impl_notifyPropertyChangeListeners( rGuard, aEvt ); +} + +bool CachedContentResultSet + ::impl_isKnownValidPosition( std::unique_lock<std::mutex>& /*rGuard*/, sal_Int32 nRow ) const +{ + return m_nKnownCount && nRow + && nRow <= m_nKnownCount; +} + +bool CachedContentResultSet + ::impl_isKnownInvalidPosition( std::unique_lock<std::mutex>& /*rGuard*/, sal_Int32 nRow ) const +{ + if( !nRow ) + return true; + if( !m_bFinalCount ) + return false; + return nRow > m_nKnownCount; +} + + +//virtual +void CachedContentResultSet + ::impl_initPropertySetInfo(std::unique_lock<std::mutex>& rGuard) +{ + ContentResultSetWrapper::impl_initPropertySetInfo(rGuard); + + if( m_xMyPropertySetInfo.is() ) + return; + m_xMyPropertySetInfo = new CCRS_PropertySetInfo( m_xPropertySetInfo ); + m_xPropertySetInfo = m_xMyPropertySetInfo.get(); +} + + +// XInterface methods. +void SAL_CALL CachedContentResultSet::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL CachedContentResultSet::release() + noexcept +{ + OWeakObject::release(); +} + +Any SAL_CALL CachedContentResultSet + ::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 ) ); + + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +// XTypeProvider methods. + +//list all interfaces exclusive baseclasses +XTYPEPROVIDER_IMPL_11( CachedContentResultSet + , XTypeProvider + , XServiceInfo + , XComponent + , XCloseable + , XResultSetMetaDataSupplier + , XPropertySet + + , XPropertyChangeListener + , XVetoableChangeListener + + , XContentAccess + + , XResultSet + , XRow ); + + +// XServiceInfo methods. + +OUString SAL_CALL CachedContentResultSet::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedContentResultSet"; +} + +sal_Bool SAL_CALL CachedContentResultSet::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL CachedContentResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedContentResultSet" }; +} + + + +// XPropertySet methods. ( inherited ) + + +// virtual +void CachedContentResultSet + ::setPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, const OUString& aPropertyName, const Any& aValue ) +{ + impl_EnsureNotDisposed(rGuard); + + if( !getPropertySetInfoImpl(rGuard).is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + + Property aProp = m_xMyPropertySetInfo->getPropertyByName( aPropertyName ); + //throws UnknownPropertyException, if so + + if( aProp.Attributes & PropertyAttribute::READONLY ) + { + //It is assumed, that the properties + //'RowCount' and 'IsRowCountFinal' are readonly! + throw IllegalArgumentException(); + } + if( aProp.Name == g_sPropertyNameForFetchDirection ) + { + //check value + sal_Int32 nNew; + if( !( aValue >>= nNew ) ) + { + throw IllegalArgumentException(); + } + + if( nNew == FetchDirection::UNKNOWN ) + { + nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_DIRECTION; + } + else if( nNew != FetchDirection::FORWARD && nNew != FetchDirection::REVERSE ) + { + throw IllegalArgumentException(); + } + + //create PropertyChangeEvent and set value + PropertyChangeEvent aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.PropertyName = aPropertyName; + aEvt.Further = false; + aEvt.PropertyHandle = m_xMyPropertySetInfo-> + m_nFetchDirectionPropertyHandle; + aEvt.OldValue <<= m_nFetchDirection; + aEvt.NewValue <<= nNew; + + m_nFetchDirection = nNew; + + //send PropertyChangeEvent to listeners + impl_notifyPropertyChangeListeners( rGuard, aEvt ); + } + else if( aProp.Name == g_sPropertyNameForFetchSize ) + { + //check value + sal_Int32 nNew; + if( !( aValue >>= nNew ) ) + { + throw IllegalArgumentException(); + } + + if( nNew < 0 ) + { + nNew = COMSUNSTARUCBCCRS_DEFAULT_FETCH_SIZE; + } + + //create PropertyChangeEvent and set value + PropertyChangeEvent aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.PropertyName = aPropertyName; + aEvt.Further = false; + aEvt.PropertyHandle = m_xMyPropertySetInfo-> + m_nFetchSizePropertyHandle; + aEvt.OldValue <<= m_nFetchSize; + aEvt.NewValue <<= nNew; + + m_nFetchSize = nNew; + + //send PropertyChangeEvent to listeners + impl_notifyPropertyChangeListeners( rGuard, aEvt ); + } + else + { + impl_init_xPropertySetOrigin(rGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return; + } + m_xPropertySetOrigin->setPropertyValue( aPropertyName, aValue ); + } +} + + +// virtual +Any SAL_CALL CachedContentResultSet + ::getPropertyValue( const OUString& rPropertyName ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !getPropertySetInfoImpl(aGuard).is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + + m_xMyPropertySetInfo->getPropertyByName( rPropertyName ); + //throws UnknownPropertyException, if so + + Any aValue; + if( rPropertyName == g_sPropertyNameForCount ) + { + aValue <<= m_nKnownCount; + } + else if( rPropertyName == g_sPropertyNameForFinalCount ) + { + aValue <<= m_bFinalCount; + } + else if( rPropertyName == g_sPropertyNameForFetchSize ) + { + aValue <<= m_nFetchSize; + } + else if( rPropertyName == g_sPropertyNameForFetchDirection ) + { + aValue <<= m_nFetchDirection; + } + else + { + impl_init_xPropertySetOrigin(aGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + aGuard.unlock(); + aValue = m_xPropertySetOrigin->getPropertyValue( rPropertyName ); + } + return aValue; +} + + +// own methods. ( inherited ) + + +//virtual, only called from ContentResultSetWrapperListener +void CachedContentResultSet + ::impl_disposing( const EventObject& rEventObject ) +{ + { + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + //release all references to the broadcaster: + m_xFetchProvider.clear(); + m_xFetchProviderForContentAccess.clear(); + } + ContentResultSetWrapper::impl_disposing( rEventObject ); +} + +//virtual, only called from ContentResultSetWrapperListener +void CachedContentResultSet + ::impl_propertyChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + + + if( CCRS_PropertySetInfo + ::impl_isMyPropertyName( rEvt.PropertyName ) ) + { + //don't notify foreign events on fetchsize and fetchdirection + if( aEvt.PropertyName == g_sPropertyNameForFetchSize + || aEvt.PropertyName == g_sPropertyNameForFetchDirection ) + return; + + //adjust my props 'RowCount' and 'IsRowCountFinal' + if( aEvt.PropertyName == g_sPropertyNameForCount ) + {//RowCount changed + + //check value + sal_Int32 nNew = 0; + if( !( aEvt.NewValue >>= nNew ) ) + { + OSL_FAIL( "PropertyChangeEvent contains wrong data" ); + return; + } + + impl_changeRowCount( aGuard, m_nKnownCount, nNew ); + } + else if( aEvt.PropertyName == g_sPropertyNameForFinalCount ) + {//IsRowCountFinal changed + + //check value + bool bNew = false; + if( !( aEvt.NewValue >>= bNew ) ) + { + OSL_FAIL( "PropertyChangeEvent contains wrong data" ); + return; + } + impl_changeIsRowCountFinal( aGuard, m_bFinalCount, bNew ); + } + return; + } + + + impl_notifyPropertyChangeListeners( aGuard, aEvt ); +} + + +//virtual, only called from ContentResultSetWrapperListener +void CachedContentResultSet + ::impl_vetoableChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //don't notify events on my properties, cause they are not vetoable + if( CCRS_PropertySetInfo + ::impl_isMyPropertyName( rEvt.PropertyName ) ) + { + return; + } + + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + + impl_notifyVetoableChangeListeners( aGuard, aEvt ); +} + + +// XContentAccess methods. ( inherited ) ( -- position dependent ) + + +#define XCONTENTACCESS_queryXXX( queryXXX, XXX, TYPE ) \ +impl_EnsureNotDisposed(rGuard); \ +sal_Int32 nRow = m_nRow; \ +sal_Int32 nFetchSize = m_nFetchSize; \ +sal_Int32 nFetchDirection = m_nFetchDirection; \ +if( !m_aCache##XXX.hasRow( nRow ) ) \ +{ \ + try \ + { \ + if( !m_aCache##XXX.hasCausedException( nRow ) ) \ + { \ + if( !m_xFetchProviderForContentAccess.is() ) \ + { \ + OSL_FAIL( "broadcaster was disposed already" ); \ + throw RuntimeException(); \ + } \ + if( impl_isForwardOnly(rGuard) ) \ + applyPositionToOrigin( rGuard, nRow ); \ + \ + FETCH_XXX( m_aCache##XXX, m_xFetchProviderForContentAccess, fetch##XXX##s ); \ + } \ + if( !m_aCache##XXX.hasRow( nRow ) ) \ + { \ + applyPositionToOrigin( rGuard, nRow ); \ + TYPE aRet = ContentResultSetWrapper::query##XXX();\ + if( m_xContentIdentifierMapping.is() ) \ + return m_xContentIdentifierMapping->map##XXX( aRet );\ + return aRet; \ + } \ + } \ + catch (const RuntimeException&) \ + { \ + throw; \ + } \ + catch (const Exception& e) \ + { \ + Any a(cppu::getCaughtException()); \ + throw WrappedTargetRuntimeException( \ + "wrapped Exception " + e.Message, \ + Reference<XInterface>(), a); \ + } \ +} \ +return m_aCache##XXX.get##XXX( nRow ); + +// virtual +OUString CachedContentResultSet + ::queryContentIdentifierStringImpl(std::unique_lock<std::mutex>& rGuard) +{ + XCONTENTACCESS_queryXXX( queryContentIdentifierString, ContentIdentifierString, OUString ) +} + + +// virtual +Reference< XContentIdentifier > SAL_CALL CachedContentResultSet + ::queryContentIdentifier() +{ + std::unique_lock rGuard(m_aMutex); + XCONTENTACCESS_queryXXX( queryContentIdentifier, ContentIdentifier, Reference< XContentIdentifier > ) +} + + +// virtual +Reference< XContent > SAL_CALL CachedContentResultSet + ::queryContent() +{ + std::unique_lock rGuard(m_aMutex); + XCONTENTACCESS_queryXXX( queryContent, Content, Reference< XContent > ) +} + + +// XResultSet methods. ( inherited ) + +//virtual + +sal_Bool SAL_CALL CachedContentResultSet + ::next() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //after last + if( m_bAfterLast ) + return false; + //last + aGuard.unlock(); + if( isLast() ) + { + aGuard.lock(); + m_nRow++; + m_bAfterLast = true; + return false; + } + aGuard.lock(); + //known valid position + if( impl_isKnownValidPosition( aGuard, m_nRow + 1 ) ) + { + m_nRow++; + return true; + } + + //unknown position + sal_Int32 nRow = m_nRow; + + bool bValid = applyPositionToOrigin( aGuard, nRow + 1 ); + + m_nRow = nRow + 1; + m_bAfterLast = !bValid; + return bValid; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::previous() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + //before first ?: + if( !m_bAfterLast && !m_nRow ) + return false; + //first ?: + if( !m_bAfterLast && m_nKnownCount && m_nRow == 1 ) + { + m_nRow--; + m_bAfterLast = false; + return false; + } + //known valid position ?: + if( impl_isKnownValidPosition( aGuard, m_nRow - 1 ) ) + { + m_nRow--; + m_bAfterLast = false; + return true; + } + //unknown position: + sal_Int32 nRow = m_nRow; + + bool bValid = applyPositionToOrigin( aGuard, nRow - 1 ); + + m_nRow = nRow - 1; + m_bAfterLast = false; + return bValid; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::absolute( sal_Int32 row ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !row ) + throw SQLException(); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } + if( row < 0 ) + { + if( m_bFinalCount ) + { + sal_Int32 nNewRow = m_nKnownCount + 1 + row; + bool bValid = true; + if( nNewRow <= 0 ) + { + nNewRow = 0; + bValid = false; + } + m_nRow = nNewRow; + m_bAfterLast = false; + return bValid; + } + //unknown final count: + aGuard.unlock(); + + bool bValid = m_xResultSetOrigin->absolute( row ); + + aGuard.lock(); + if( m_bFinalCount ) + { + sal_Int32 nNewRow = m_nKnownCount + 1 + row; + if( nNewRow < 0 ) + nNewRow = 0; + m_nLastAppliedPos = nNewRow; + m_nRow = nNewRow; + m_bAfterLastApplied = m_bAfterLast = false; + return bValid; + } + aGuard.unlock(); + + sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); + + aGuard.lock(); + m_nLastAppliedPos = nCurRow; + m_nRow = nCurRow; + m_bAfterLast = false; + return nCurRow != 0; + } + //row > 0: + if( m_bFinalCount ) + { + if( row > m_nKnownCount ) + { + m_nRow = m_nKnownCount + 1; + m_bAfterLast = true; + return false; + } + m_nRow = row; + m_bAfterLast = false; + return true; + } + //unknown new position: + aGuard.unlock(); + + bool bValid = m_xResultSetOrigin->absolute( row ); + + aGuard.lock(); + if( m_bFinalCount ) + { + sal_Int32 nNewRow = row; + if( nNewRow > m_nKnownCount ) + { + nNewRow = m_nKnownCount + 1; + m_bAfterLastApplied = m_bAfterLast = true; + } + else + m_bAfterLastApplied = m_bAfterLast = false; + + m_nLastAppliedPos = nNewRow; + m_nRow = nNewRow; + return bValid; + } + aGuard.unlock(); + + sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); + bool bIsAfterLast = m_xResultSetOrigin->isAfterLast(); + + aGuard.lock(); + m_nLastAppliedPos = nCurRow; + m_nRow = nCurRow; + m_bAfterLastApplied = m_bAfterLast = bIsAfterLast; + return nCurRow && !bIsAfterLast; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::relative( sal_Int32 rows ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + if( m_bAfterLast || impl_isKnownInvalidPosition( aGuard, m_nRow ) ) + throw SQLException(); + + if( !rows ) + return true; + + sal_Int32 nNewRow = m_nRow + rows; + if( nNewRow < 0 ) + nNewRow = 0; + + if( impl_isKnownValidPosition( aGuard, nNewRow ) ) + { + m_nRow = nNewRow; + m_bAfterLast = false; + return true; + } + else + { + //known invalid new position: + if( nNewRow == 0 ) + { + m_bAfterLast = false; + m_nRow = 0; + return false; + } + if( m_bFinalCount && nNewRow > m_nKnownCount ) + { + m_bAfterLast = true; + m_nRow = m_nKnownCount + 1; + return false; + } + //unknown new position: + bool bValid = applyPositionToOrigin( aGuard, nNewRow ); + m_nRow = nNewRow; + m_bAfterLast = !bValid; // only nNewRow > 0 possible here + return bValid; + } +} + + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::first() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + if( impl_isKnownValidPosition( aGuard, 1 ) ) + { + m_nRow = 1; + m_bAfterLast = false; + return true; + } + if( impl_isKnownInvalidPosition( aGuard, 1 ) ) + { + m_nRow = 1; + m_bAfterLast = false; + return false; + } + //unknown position + bool bValid = applyPositionToOrigin( aGuard, 1 ); + m_nRow = 1; + m_bAfterLast = false; + return bValid; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::last() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + if( m_bFinalCount ) + { + m_nRow = m_nKnownCount; + m_bAfterLast = false; + return m_nKnownCount != 0; + } + //unknown position + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } + aGuard.unlock(); + + bool bValid = m_xResultSetOrigin->last(); + + aGuard.lock(); + m_bAfterLastApplied = m_bAfterLast = false; + if( m_bFinalCount ) + { + m_nLastAppliedPos = m_nKnownCount; + m_nRow = m_nKnownCount; + return bValid; + } + aGuard.unlock(); + + sal_Int32 nCurRow = m_xResultSetOrigin->getRow(); + + aGuard.lock(); + m_nLastAppliedPos = nCurRow; + m_nRow = nCurRow; + OSL_ENSURE( nCurRow >= m_nKnownCount, "position of last row < known Count, that could not be" ); + m_nKnownCount = nCurRow; + m_bFinalCount = true; + return nCurRow != 0; +} + +//virtual +void SAL_CALL CachedContentResultSet + ::beforeFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + m_nRow = 0; + m_bAfterLast = false; +} + +//virtual +void SAL_CALL CachedContentResultSet + ::afterLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( impl_isForwardOnly(aGuard) ) + throw SQLException(); + + m_nRow = 1; + m_bAfterLast = true; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::isAfterLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_bAfterLast ) + return false; + if( m_nKnownCount ) + return m_bAfterLast; + if( m_bFinalCount ) + return false; + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } + aGuard.unlock(); + + //find out whether the original resultset contains rows or not + m_xResultSetOrigin->afterLast(); + + aGuard.lock(); + m_bAfterLastApplied = true; + aGuard.unlock(); + + return m_xResultSetOrigin->isAfterLast(); +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::isBeforeFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( m_bAfterLast ) + return false; + if( m_nRow ) + return false; + if( m_nKnownCount ) + return true; + if( m_bFinalCount ) + return false; + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } + aGuard.unlock(); + + //find out whether the original resultset contains rows or not + m_xResultSetOrigin->beforeFirst(); + + aGuard.lock(); + m_bAfterLastApplied = false; + m_nLastAppliedPos = 0; + aGuard.unlock(); + + return m_xResultSetOrigin->isBeforeFirst(); +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::isFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + sal_Int32 nRow = 0; + Reference< XResultSet > xResultSetOrigin; + + if( m_bAfterLast ) + return false; + if( m_nRow != 1 ) + return false; + if( m_nKnownCount ) + return true; + if( m_bFinalCount ) + return false; + + nRow = m_nRow; + xResultSetOrigin = m_xResultSetOrigin; + + //need to ask origin + if( !applyPositionToOrigin( aGuard, nRow ) ) + return false; + aGuard.unlock(); + return xResultSetOrigin->isFirst(); +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::isLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + sal_Int32 nRow = 0; + Reference< XResultSet > xResultSetOrigin; + if( m_bAfterLast ) + return false; + if( m_nRow < m_nKnownCount ) + return false; + if( m_bFinalCount ) + return m_nKnownCount && m_nRow == m_nKnownCount; + + nRow = m_nRow; + xResultSetOrigin = m_xResultSetOrigin; + + //need to ask origin + if( !applyPositionToOrigin( aGuard, nRow ) ) + return false; + aGuard.unlock(); + return xResultSetOrigin->isLast(); +} + + +//virtual +sal_Int32 SAL_CALL CachedContentResultSet + ::getRow() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( m_bAfterLast ) + return 0; + return m_nRow; +} + +//virtual +void SAL_CALL CachedContentResultSet + ::refreshRow() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //the ContentResultSet is static and will not change + //therefore we don't need to reload anything +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::rowUpdated() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //the ContentResultSet is static and will not change + return false; +} +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::rowInserted() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //the ContentResultSet is static and will not change + return false; +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::rowDeleted() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //the ContentResultSet is static and will not change + return false; +} + +//virtual +Reference< XInterface > SAL_CALL CachedContentResultSet + ::getStatement() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + //@todo ?return anything + return Reference< XInterface >(); +} + + +// XRow methods. ( inherited ) + + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::wasNull() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xRowOrigin(aGuard); + if( m_bLastReadWasFromCache ) + return m_bLastCachedReadWasNull; + if( !m_xRowOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return false; + } + aGuard.unlock(); + return m_xRowOrigin->wasNull(); +} + +//virtual +OUString SAL_CALL CachedContentResultSet + ::getString( sal_Int32 columnIndex ) +{ + return rowOriginGet<OUString>(&css::sdbc::XRow::getString, columnIndex); +} + +//virtual +sal_Bool SAL_CALL CachedContentResultSet + ::getBoolean( sal_Int32 columnIndex ) +{ + return rowOriginGet<sal_Bool>(&css::sdbc::XRow::getBoolean, columnIndex); +} + +//virtual +sal_Int8 SAL_CALL CachedContentResultSet + ::getByte( sal_Int32 columnIndex ) +{ + return rowOriginGet<sal_Int8>(&css::sdbc::XRow::getByte, columnIndex); +} + +//virtual +sal_Int16 SAL_CALL CachedContentResultSet + ::getShort( sal_Int32 columnIndex ) +{ + return rowOriginGet<sal_Int16>(&css::sdbc::XRow::getShort, columnIndex); +} + +//virtual +sal_Int32 SAL_CALL CachedContentResultSet + ::getInt( sal_Int32 columnIndex ) +{ + return rowOriginGet<sal_Int32>(&css::sdbc::XRow::getInt, columnIndex); +} + +//virtual +sal_Int64 SAL_CALL CachedContentResultSet + ::getLong( sal_Int32 columnIndex ) +{ + return rowOriginGet<sal_Int64>(&css::sdbc::XRow::getLong, columnIndex); +} + +//virtual +float SAL_CALL CachedContentResultSet + ::getFloat( sal_Int32 columnIndex ) +{ + return rowOriginGet<float>(&css::sdbc::XRow::getFloat, columnIndex); +} + +//virtual +double SAL_CALL CachedContentResultSet + ::getDouble( sal_Int32 columnIndex ) +{ + return rowOriginGet<double>(&css::sdbc::XRow::getDouble, columnIndex); +} + +//virtual +Sequence< sal_Int8 > SAL_CALL CachedContentResultSet + ::getBytes( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Sequence<sal_Int8> >( + &css::sdbc::XRow::getBytes, columnIndex); +} + +//virtual +Date SAL_CALL CachedContentResultSet + ::getDate( sal_Int32 columnIndex ) +{ + return rowOriginGet<css::util::Date>( + &css::sdbc::XRow::getDate, columnIndex); +} + +//virtual +Time SAL_CALL CachedContentResultSet + ::getTime( sal_Int32 columnIndex ) +{ + return rowOriginGet<css::util::Time>( + &css::sdbc::XRow::getTime, columnIndex); +} + +//virtual +DateTime SAL_CALL CachedContentResultSet + ::getTimestamp( sal_Int32 columnIndex ) +{ + return rowOriginGet<css::util::DateTime>( + &css::sdbc::XRow::getTimestamp, columnIndex); +} + +//virtual +Reference< css::io::XInputStream > + SAL_CALL CachedContentResultSet + ::getBinaryStream( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::io::XInputStream> >( + &css::sdbc::XRow::getBinaryStream, columnIndex); +} + +//virtual +Reference< css::io::XInputStream > + SAL_CALL CachedContentResultSet + ::getCharacterStream( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::io::XInputStream> >( + &css::sdbc::XRow::getCharacterStream, columnIndex); +} + +//virtual +Any SAL_CALL CachedContentResultSet + ::getObject( sal_Int32 columnIndex, + const Reference< + css::container::XNameAccess >& typeMap ) +{ + //if you change this function please pay attention to + //function template rowOriginGet, where this is similar implemented + + std::unique_lock aGuard(m_aMutex); + sal_Int32 nRow = m_nRow; + sal_Int32 nFetchSize = m_nFetchSize; + sal_Int32 nFetchDirection = m_nFetchDirection; + if( !m_aCache.hasRow( nRow ) ) + { + if( !m_aCache.hasCausedException( nRow ) ) + { + if( !m_xFetchProvider.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return Any(); + } + impl_fetchData( aGuard, nRow, nFetchSize, nFetchDirection ); + } + if( !m_aCache.hasRow( nRow ) ) + { + m_bLastReadWasFromCache = false; + applyPositionToOrigin( aGuard, nRow ); + impl_init_xRowOrigin(aGuard); + aGuard.unlock(); + return m_xRowOrigin->getObject( columnIndex, typeMap ); + } + } + //@todo: pay attention to typeMap + const Any& rValue = m_aCache.getAny( nRow, columnIndex ); + m_bLastReadWasFromCache = true; + m_bLastCachedReadWasNull = !rValue.hasValue(); + return rValue; +} + +//virtual +Reference< XRef > SAL_CALL CachedContentResultSet + ::getRef( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::sdbc::XRef> >( + &css::sdbc::XRow::getRef, columnIndex); +} + +//virtual +Reference< XBlob > SAL_CALL CachedContentResultSet + ::getBlob( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::sdbc::XBlob> >( + &css::sdbc::XRow::getBlob, columnIndex); +} + +//virtual +Reference< XClob > SAL_CALL CachedContentResultSet + ::getClob( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::sdbc::XClob> >( + &css::sdbc::XRow::getClob, columnIndex); +} + +//virtual +Reference< XArray > SAL_CALL CachedContentResultSet + ::getArray( sal_Int32 columnIndex ) +{ + return rowOriginGet< css::uno::Reference<css::sdbc::XArray> >( + &css::sdbc::XRow::getArray, columnIndex); +} + + +// Type Converter Support + + +const Reference< XTypeConverter >& CachedContentResultSet::getTypeConverter(std::unique_lock<std::mutex>& ) +{ + if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() ) + { + m_bTriedToGetTypeConverter = true; + m_xTypeConverter.set( Converter::create(m_xContext) ); + + OSL_ENSURE( m_xTypeConverter.is(), + "PropertyValueSet::getTypeConverter() - " + "Service 'com.sun.star.script.Converter' n/a!" ); + } + return m_xTypeConverter; +} + + + + +CachedContentResultSetFactory::CachedContentResultSetFactory( + const Reference< XComponentContext > & rxContext ) +{ + m_xContext = rxContext; +} + +CachedContentResultSetFactory::~CachedContentResultSetFactory() +{ +} + +// CachedContentResultSetFactory XServiceInfo methods. + +OUString SAL_CALL CachedContentResultSetFactory::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedContentResultSetFactory"; +} +sal_Bool SAL_CALL CachedContentResultSetFactory::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} +css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedContentResultSetFactory" }; +} + +// Service factory implementation. + + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_CachedContentResultSetFactory_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new CachedContentResultSetFactory(context)); +} + + +// CachedContentResultSetFactory XCachedContentResultSetFactory methods. + + + //virtual +Reference< XResultSet > SAL_CALL CachedContentResultSetFactory + ::createCachedContentResultSet( + const Reference< XResultSet > & xSource, + const Reference< XContentIdentifierMapping > & xMapping ) +{ + Reference< XResultSet > xRet = new CachedContentResultSet( m_xContext, xSource, xMapping ); + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cachedcontentresultset.hxx b/ucb/source/cacher/cachedcontentresultset.hxx new file mode 100644 index 0000000000..4bca955ee7 --- /dev/null +++ b/ucb/source/cacher/cachedcontentresultset.hxx @@ -0,0 +1,386 @@ +/* -*- 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 . + */ + +#pragma once + +#include "contentresultsetwrapper.hxx" +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/ucb/XFetchProvider.hpp> +#include <com/sun/star/ucb/XFetchProviderForContentAccess.hpp> +#include <com/sun/star/ucb/FetchResult.hpp> +#include <com/sun/star/ucb/XContentIdentifierMapping.hpp> +#include <com/sun/star/ucb/XCachedContentResultSetFactory.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +#include <optional> + +namespace com::sun::star::script { + class XTypeConverter; +} + +class CCRS_PropertySetInfo; +class CachedContentResultSet + : public ContentResultSetWrapper + , public css::lang::XTypeProvider + , public css::lang::XServiceInfo +{ + + + class CCRS_Cache + { + private: + std::optional<css::ucb::FetchResult> + m_pResult; + css::uno::Reference< css::ucb::XContentIdentifierMapping > + m_xContentIdentifierMapping; + std::optional<css::uno::Sequence< sal_Bool >> m_pMappedReminder; + + private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Any& + getRowAny( sal_Int32 nRow ); + + void clear(); + + + void remindMapped( sal_Int32 nRow ); + bool isRowMapped( sal_Int32 nRow ); + css::uno::Sequence< sal_Bool >& getMappedReminder(); + + public: + CCRS_Cache( const css::uno::Reference< + css::ucb::XContentIdentifierMapping > & xMapping ); + ~CCRS_Cache(); + + void loadData( + const css::ucb::FetchResult& rResult ); + + bool + hasRow( sal_Int32 nRow ) const; + + bool + hasCausedException( sal_Int32 nRow ) const; + + sal_Int32 + getMaxRow() const; + + bool + hasKnownLast() const; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + const css::uno::Any& + getAny( sal_Int32 nRow, sal_Int32 nColumnIndex ); + + /// @throws css::uno::RuntimeException + OUString const & + getContentIdentifierString( sal_Int32 nRow ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::ucb::XContentIdentifier > + getContentIdentifier( sal_Int32 nRow ); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::ucb::XContent > + getContent( sal_Int32 nRow ); + }; + + //members + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + //different Interfaces from Origin: + css::uno::Reference< css::ucb::XFetchProvider > + m_xFetchProvider; //XFetchProvider-interface from m_xOrigin + + css::uno::Reference< css::ucb::XFetchProviderForContentAccess > + m_xFetchProviderForContentAccess; //XFetchProviderForContentAccess-interface from m_xOrigin + + rtl::Reference< CCRS_PropertySetInfo > + m_xMyPropertySetInfo; + + + css::uno::Reference< css::ucb::XContentIdentifierMapping > + m_xContentIdentifierMapping;// can be used for remote optimized ContentAccess + + //some Properties and helping variables + sal_Int32 m_nRow; + bool m_bAfterLast; // TRUE, if m_nRow is after final count; can be TRUE without knowing the exact final count + + sal_Int32 m_nLastAppliedPos; + bool m_bAfterLastApplied; + + sal_Int32 m_nKnownCount; // count we know from the Origin + bool m_bFinalCount; // TRUE if the Origin has reached final count and we got that count in m_nKnownCount + + sal_Int32 m_nFetchSize; + sal_Int32 m_nFetchDirection; + + bool m_bLastReadWasFromCache; + bool m_bLastCachedReadWasNull; + + //cache: + CCRS_Cache m_aCache; + CCRS_Cache m_aCacheContentIdentifierString; + CCRS_Cache m_aCacheContentIdentifier; + CCRS_Cache m_aCacheContent; + + +private: + + //helping XPropertySet methods. + virtual void impl_initPropertySetInfo(std::unique_lock<std::mutex>& rGuard) override; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool + applyPositionToOrigin( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow ); + + /// @throws css::uno::RuntimeException + void + impl_fetchData( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow, sal_Int32 nCount + , sal_Int32 nFetchDirection ); + + bool + impl_isKnownValidPosition( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow ) const; + + bool + impl_isKnownInvalidPosition( std::unique_lock<std::mutex>& rGuard, sal_Int32 nRow ) const; + + void + impl_changeRowCount( std::unique_lock<std::mutex>& rGuard, sal_Int32 nOld, sal_Int32 nNew ); + + void + impl_changeIsRowCountFinal( std::unique_lock<std::mutex>& rGuard, bool bOld, bool bNew ); + +public: + CachedContentResultSet( + const css::uno::Reference< css::uno::XComponentContext > & rxContext, + const css::uno::Reference< css::sdbc::XResultSet > & xOrigin, + const css::uno::Reference< css::ucb::XContentIdentifierMapping > & xContentIdentifierMapping ); + + virtual ~CachedContentResultSet() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XPropertySet inherited + + + virtual void + setPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + + virtual css::uno::Any SAL_CALL + getPropertyValue( const OUString& PropertyName ) override; + + + // own inherited + + virtual void + impl_disposing( const css::lang::EventObject& Source ) override; + + virtual void + impl_propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + virtual void + impl_vetoableChange( const css::beans::PropertyChangeEvent& aEvent ) override; + + + // XContentAccess inherited + + virtual OUString + queryContentIdentifierStringImpl(std::unique_lock<std::mutex>& rGuard) override; + + virtual css::uno::Reference< + css::ucb::XContentIdentifier > SAL_CALL + queryContentIdentifier() override; + + virtual css::uno::Reference< + css::ucb::XContent > SAL_CALL + queryContent() override; + + + // XResultSet inherited + + virtual sal_Bool SAL_CALL + next() override; + virtual sal_Bool SAL_CALL + isBeforeFirst() override; + virtual sal_Bool SAL_CALL + isAfterLast() override; + virtual sal_Bool SAL_CALL + isFirst() override; + virtual sal_Bool SAL_CALL + isLast() override; + virtual void SAL_CALL + beforeFirst() override; + virtual void SAL_CALL + afterLast() override; + virtual sal_Bool SAL_CALL + first() override; + virtual sal_Bool SAL_CALL + last() override; + virtual sal_Int32 SAL_CALL + getRow() override; + virtual sal_Bool SAL_CALL + absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL + relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL + previous() override; + virtual void SAL_CALL + refreshRow() override; + virtual sal_Bool SAL_CALL + rowUpdated() override; + virtual sal_Bool SAL_CALL + rowInserted() override; + virtual sal_Bool SAL_CALL + rowDeleted() override; + virtual css::uno::Reference< + css::uno::XInterface > SAL_CALL + getStatement() override; + + + // XRow inherited + + virtual sal_Bool SAL_CALL + wasNull() override; + + virtual OUString SAL_CALL + getString( sal_Int32 columnIndex ) override; + + virtual sal_Bool SAL_CALL + getBoolean( sal_Int32 columnIndex ) override; + + virtual sal_Int8 SAL_CALL + getByte( sal_Int32 columnIndex ) override; + + virtual sal_Int16 SAL_CALL + getShort( sal_Int32 columnIndex ) override; + + virtual sal_Int32 SAL_CALL + getInt( sal_Int32 columnIndex ) override; + + virtual sal_Int64 SAL_CALL + getLong( sal_Int32 columnIndex ) override; + + virtual float SAL_CALL + getFloat( sal_Int32 columnIndex ) override; + + virtual double SAL_CALL + getDouble( sal_Int32 columnIndex ) override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes( sal_Int32 columnIndex ) override; + + virtual css::util::Date SAL_CALL + getDate( sal_Int32 columnIndex ) override; + + virtual css::util::Time SAL_CALL + getTime( sal_Int32 columnIndex ) override; + + virtual css::util::DateTime SAL_CALL + getTimestamp( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Any SAL_CALL + getObject( sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL + getRef( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL + getBlob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL + getClob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL + getArray( sal_Int32 columnIndex ) override; + + + // Type Converter support + + +private: + bool m_bTriedToGetTypeConverter; + css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter; + + const css::uno::Reference< + css::script::XTypeConverter >& getTypeConverter(std::unique_lock<std::mutex>& rGuard); + + template<typename T> T rowOriginGet( + T (SAL_CALL css::sdbc::XRow::* f)(sal_Int32), sal_Int32 columnIndex); +}; + + +class CachedContentResultSetFactory final : + public cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::ucb::XCachedContentResultSetFactory> +{ + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +public: + + CachedContentResultSetFactory( const css::uno::Reference< css::uno::XComponentContext > & rxContext); + + virtual ~CachedContentResultSetFactory() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XCachedContentResultSetFactory + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + createCachedContentResultSet( + const css::uno::Reference< css::sdbc::XResultSet > & xSource, + const css::uno::Reference< css::ucb::XContentIdentifierMapping > & xMapping ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cachedcontentresultsetstub.cxx b/ucb/source/cacher/cachedcontentresultsetstub.cxx new file mode 100644 index 0000000000..d1b96abf43 --- /dev/null +++ b/ucb/source/cacher/cachedcontentresultsetstub.cxx @@ -0,0 +1,551 @@ +/* -*- 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, only called from ContentResultSetWrapperListener +void CachedContentResultSetStub + ::impl_propertyChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //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( aGuard, aEvt ); +} + + +//virtual, only called from ContentResultSetWrapperListener +void CachedContentResultSetStub + ::impl_vetoableChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + //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( aGuard, 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( + std::unique_lock<std::mutex>& rGuard, + sal_Int32 nRowStartPosition, sal_Int32 nRowCount, bool bDirection, + std::function<void( std::unique_lock<std::mutex>&, css::uno::Any& rRowContent)> impl_loadRow) +{ + impl_EnsureNotDisposed(rGuard); + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + impl_propagateFetchSizeAndDirection( rGuard, 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(rGuard) ) + { + 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( rGuard, 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( rGuard, 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 ) +{ + std::unique_lock aGuard(m_aMutex); + impl_init_xRowOrigin(aGuard); + return impl_fetchHelper( aGuard, nRowStartPosition, nRowCount, bDirection, + [&](std::unique_lock<std::mutex>& rGuard, css::uno::Any& rRowContent) + { return impl_getCurrentRowContent(rGuard, rRowContent, m_xRowOrigin); }); +} + +sal_Int32 CachedContentResultSetStub + ::impl_getColumnCount(std::unique_lock<std::mutex>& /*rGuard*/) +{ + sal_Int32 nCount; + bool bCached; + 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; + } + } + m_nColumnCount = nCount; + m_bColumnCountCached = true; + return m_nColumnCount; +} + +void CachedContentResultSetStub + ::impl_getCurrentRowContent( std::unique_lock<std::mutex>& rGuard, Any& rRowContent + , const Reference< XRow >& xRow ) +{ + sal_Int32 nCount = impl_getColumnCount(rGuard); + + 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( std::unique_lock<std::mutex>& rGuard, 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; + 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) + { + m_bNeedToPropagateFetchSize = false; + return; + } + } + + bool bSetSize = ( nLastSize !=nFetchSize ) || !bFirstPropagationDone; + bool bSetDirection = ( bLastDirection !=bFetchDirection ) || !bFirstPropagationDone; + + m_bFirstFetchSizePropagationDone = true; + m_nLastFetchSize = nFetchSize; + m_bLastFetchDirection = bFetchDirection; + + if( bSetSize ) + { + Any aValue; + aValue <<= nFetchSize; + try + { + setPropertyValueImpl( rGuard, 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 + { + setPropertyValueImpl( rGuard, m_aPropertyNameForFetchDirection, aValue ); + } + catch( css::uno::Exception& ) {} +} + + +// XFetchProviderForContentAccess methods. + + +void CachedContentResultSetStub + ::impl_getCurrentContentIdentifierString( std::unique_lock<std::mutex>& /*rGuard*/, Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContentIdentifierString(); +} + +void CachedContentResultSetStub + ::impl_getCurrentContentIdentifier( std::unique_lock<std::mutex>& /*rGuard*/, Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContentIdentifier(); +} + +void CachedContentResultSetStub + ::impl_getCurrentContent( std::unique_lock<std::mutex>& /*rGuard*/, Any& rAny + , const Reference< XContentAccess >& xContentAccess ) +{ + rAny <<= xContentAccess->queryContent(); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContentIdentifierStrings( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_init_xContentAccessOrigin(aGuard); + return impl_fetchHelper( aGuard, nRowStartPosition, nRowCount, bDirection, + [&](std::unique_lock<std::mutex>& rGuard, css::uno::Any& rRowContent) + { return impl_getCurrentContentIdentifierString(rGuard, rRowContent, m_xContentAccessOrigin); }); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContentIdentifiers( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_init_xContentAccessOrigin(aGuard); + return impl_fetchHelper( aGuard, nRowStartPosition, nRowCount, bDirection, + [&](std::unique_lock<std::mutex>& rGuard, css::uno::Any& rRowContent) + { return impl_getCurrentContentIdentifier(rGuard, rRowContent, m_xContentAccessOrigin); }); +} + +//virtual +FetchResult SAL_CALL CachedContentResultSetStub + ::fetchContents( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_init_xContentAccessOrigin(aGuard); + return impl_fetchHelper( aGuard, nRowStartPosition, nRowCount, bDirection, + [&](std::unique_lock<std::mutex>& rGuard, css::uno::Any& rRowContent) + { return impl_getCurrentContent(rGuard, 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: */ diff --git a/ucb/source/cacher/cachedcontentresultsetstub.hxx b/ucb/source/cacher/cachedcontentresultsetstub.hxx new file mode 100644 index 0000000000..23c66f828c --- /dev/null +++ b/ucb/source/cacher/cachedcontentresultsetstub.hxx @@ -0,0 +1,168 @@ +/* -*- 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 . + */ + +#pragma once + +#include "contentresultsetwrapper.hxx" +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/ucb/XFetchProvider.hpp> +#include <com/sun/star/ucb/XFetchProviderForContentAccess.hpp> +#include <com/sun/star/ucb/XCachedContentResultSetStubFactory.hpp> +#include <cppuhelper/implbase.hxx> + +class CachedContentResultSetStub + : public ContentResultSetWrapper + , public css::lang::XTypeProvider + , public css::lang::XServiceInfo + , public css::ucb::XFetchProvider + , public css::ucb::XFetchProviderForContentAccess +{ +private: + sal_Int32 m_nColumnCount; + bool m_bColumnCountCached; + + //members to propagate fetchsize and direction: + bool m_bNeedToPropagateFetchSize; + bool m_bFirstFetchSizePropagationDone; + sal_Int32 m_nLastFetchSize; + bool m_bLastFetchDirection; + const OUString m_aPropertyNameForFetchSize; + const OUString m_aPropertyNameForFetchDirection; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void + impl_getCurrentRowContent( + std::unique_lock<std::mutex>& rGuard, + css::uno::Any& rRowContent, + const css::uno::Reference< css::sdbc::XRow >& xRow ); + + sal_Int32 + impl_getColumnCount(std::unique_lock<std::mutex>&); + + /// @throws css::uno::RuntimeException + static void + impl_getCurrentContentIdentifierString( + std::unique_lock<std::mutex>& rGuard, + css::uno::Any& rAny + , const css::uno::Reference< css::ucb::XContentAccess >& xContentAccess ); + + /// @throws css::uno::RuntimeException + static void + impl_getCurrentContentIdentifier( + std::unique_lock<std::mutex>& rGuard, + css::uno::Any& rAny + , const css::uno::Reference< css::ucb::XContentAccess >& xContentAccess ); + + /// @throws css::uno::RuntimeException + static void + impl_getCurrentContent( + std::unique_lock<std::mutex>& rGuard, + css::uno::Any& rAny + , const css::uno::Reference< css::ucb::XContentAccess >& xContentAccess ); + + /// @throws css::uno::RuntimeException + void + impl_propagateFetchSizeAndDirection( std::unique_lock<std::mutex>& rGuard, sal_Int32 nFetchSize, bool bFetchDirection ); + + css::ucb::FetchResult impl_fetchHelper( + std::unique_lock<std::mutex>& rGuard, + sal_Int32 nRowStartPosition, sal_Int32 nRowCount, bool bDirection, + std::function<void(std::unique_lock<std::mutex>&, css::uno::Any& rRowContent)> impl_loadRow); + +public: + CachedContentResultSetStub( css::uno::Reference< css::sdbc::XResultSet > const & xOrigin ); + + virtual ~CachedContentResultSetStub() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // own inherited + + virtual void + impl_propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + virtual void + impl_vetoableChange( const css::beans::PropertyChangeEvent& aEvent ) override; + + // XTypeProvider + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XFetchProvider + + + virtual css::ucb::FetchResult SAL_CALL + fetch( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) override; + + + // XFetchProviderForContentAccess + + virtual css::ucb::FetchResult SAL_CALL + fetchContentIdentifierStrings( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) override; + + virtual css::ucb::FetchResult SAL_CALL + fetchContentIdentifiers( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) override; + + virtual css::ucb::FetchResult SAL_CALL + fetchContents( sal_Int32 nRowStartPosition + , sal_Int32 nRowCount, sal_Bool bDirection ) override; +}; + + +class CachedContentResultSetStubFactory final : + public cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::ucb::XCachedContentResultSetStubFactory> +{ +public: + + CachedContentResultSetStubFactory(); + + virtual ~CachedContentResultSetStubFactory() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XCachedContentResultSetStubFactory + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + createCachedContentResultSetStub( + const css::uno::Reference< css::sdbc::XResultSet > & xSource ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cacheddynamicresultset.cxx b/ucb/source/cacher/cacheddynamicresultset.cxx new file mode 100644 index 0000000000..acb00ef679 --- /dev/null +++ b/ucb/source/cacher/cacheddynamicresultset.cxx @@ -0,0 +1,200 @@ +/* -*- 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 "cacheddynamicresultset.hxx" +#include "cachedcontentresultset.hxx" +#include <osl/diagnose.h> +#include <cppuhelper/queryinterface.hxx> +#include <ucbhelper/macros.hxx> + +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + + +CachedDynamicResultSet::CachedDynamicResultSet( + Reference< XDynamicResultSet > const & xOrigin + , const Reference< XContentIdentifierMapping > & xContentMapping + , const Reference< XComponentContext > & xContext ) + : DynamicResultSetWrapper( xOrigin, xContext ) + , m_xContentIdentifierMapping( xContentMapping ) +{ + impl_init(); +} + +CachedDynamicResultSet::~CachedDynamicResultSet() +{ + impl_deinit(); +} + +//virtual +void CachedDynamicResultSet + ::impl_InitResultSetOne( const Reference< XResultSet >& xResultSet ) +{ + DynamicResultSetWrapper::impl_InitResultSetOne( xResultSet ); + OSL_ENSURE( m_xSourceResultOne.is(), "need source resultset" ); + + Reference< XResultSet > xCache( + new CachedContentResultSet( m_xContext, m_xSourceResultOne, m_xContentIdentifierMapping ) ); + + std::unique_lock aGuard( m_aMutex ); + m_xMyResultOne = xCache; +} + +//virtual +void CachedDynamicResultSet + ::impl_InitResultSetTwo( const Reference< XResultSet >& xResultSet ) +{ + DynamicResultSetWrapper::impl_InitResultSetTwo( xResultSet ); + OSL_ENSURE( m_xSourceResultTwo.is(), "need source resultset" ); + + Reference< XResultSet > xCache( + new CachedContentResultSet( m_xContext, m_xSourceResultTwo, m_xContentIdentifierMapping ) ); + + std::unique_lock aGuard( m_aMutex ); + m_xMyResultTwo = xCache; +} + + +// XInterface methods. +void SAL_CALL CachedDynamicResultSet::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL CachedDynamicResultSet::release() + noexcept +{ + OWeakObject::release(); +} + +Any SAL_CALL CachedDynamicResultSet + ::queryInterface( const Type& rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + + Any aRet = DynamicResultSetWrapper::queryInterface( rType ); + if( aRet.hasValue() ) + return aRet; + + aRet = cppu::queryInterface( rType, + static_cast< XTypeProvider* >( this ) + , static_cast< XServiceInfo* >( this ) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +// XTypeProvider methods. + +//list all interfaces exclusive baseclasses +XTYPEPROVIDER_IMPL_4( CachedDynamicResultSet + , XTypeProvider + , XServiceInfo + , XDynamicResultSet + , XSourceInitialization + ); + + +// XServiceInfo methods. + +OUString SAL_CALL CachedDynamicResultSet::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedDynamicResultSet"; +} + +sal_Bool SAL_CALL CachedDynamicResultSet::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL CachedDynamicResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedDynamicResultSet" }; +} + + +// own methods. ( inherited ) + +//virtual +void CachedDynamicResultSet + ::impl_disposing( const EventObject& Source ) +{ + DynamicResultSetWrapper::impl_disposing( Source ); + m_xContentIdentifierMapping.clear(); +} + + + + +CachedDynamicResultSetFactory::CachedDynamicResultSetFactory( + const Reference< XComponentContext > & xContext ) +{ + m_xContext = xContext; +} + +CachedDynamicResultSetFactory::~CachedDynamicResultSetFactory() +{ +} + + +// CachedDynamicResultSetFactory XServiceInfo methods. + +OUString SAL_CALL CachedDynamicResultSetFactory::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedDynamicResultSetFactory"; +} +sal_Bool SAL_CALL CachedDynamicResultSetFactory::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} +css::uno::Sequence< OUString > SAL_CALL CachedDynamicResultSetFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedDynamicResultSetFactory" }; +} + +// Service factory implementation. + + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_CachedDynamicResultSetFactory_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new CachedDynamicResultSetFactory(context)); +} + +// CachedDynamicResultSetFactory XCachedDynamicResultSetFactory methods. + + +//virtual +Reference< XDynamicResultSet > SAL_CALL CachedDynamicResultSetFactory + ::createCachedDynamicResultSet( + const Reference< XDynamicResultSet > & SourceStub + , const Reference< XContentIdentifierMapping > & ContentIdentifierMapping ) +{ + Reference< XDynamicResultSet > xRet = new CachedDynamicResultSet( SourceStub, ContentIdentifierMapping, m_xContext ); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cacheddynamicresultset.hxx b/ucb/source/cacher/cacheddynamicresultset.hxx new file mode 100644 index 0000000000..76075b98eb --- /dev/null +++ b/ucb/source/cacher/cacheddynamicresultset.hxx @@ -0,0 +1,104 @@ +/* -*- 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 . + */ + +#pragma once + +#include "dynamicresultsetwrapper.hxx" +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/ucb/XContentIdentifierMapping.hpp> +#include <com/sun/star/ucb/XCachedDynamicResultSetFactory.hpp> +#include <cppuhelper/implbase.hxx> + + +class CachedDynamicResultSet + : public DynamicResultSetWrapper + , public css::lang::XTypeProvider + , public css::lang::XServiceInfo +{ + css::uno::Reference< css::ucb::XContentIdentifierMapping > + m_xContentIdentifierMapping; + +protected: + virtual void + impl_InitResultSetOne( const css::uno::Reference< css::sdbc::XResultSet >& xResultSet ) override; + virtual void + impl_InitResultSetTwo( const css::uno::Reference< css::sdbc::XResultSet >& xResultSet ) override; + +public: + CachedDynamicResultSet( css::uno::Reference< css::ucb::XDynamicResultSet > const & xOrigin + , const css::uno::Reference< css::ucb::XContentIdentifierMapping > & xContentMapping + , const css::uno::Reference< css::uno::XComponentContext > & xContext ); + + virtual ~CachedDynamicResultSet() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // own methods ( inherited ) + + virtual void + impl_disposing( const css::lang::EventObject& Source ) override; +}; + + +class CachedDynamicResultSetFactory final : + public cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::ucb::XCachedDynamicResultSetFactory> +{ + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +public: + + CachedDynamicResultSetFactory( + const css::uno::Reference< css::uno::XComponentContext > & xContext); + + virtual ~CachedDynamicResultSetFactory() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XCachedDynamicResultSetFactory + + virtual css::uno::Reference< css::ucb::XDynamicResultSet > SAL_CALL + createCachedDynamicResultSet( + const css::uno::Reference< css::ucb::XDynamicResultSet > & SourceStub + , const css::uno::Reference< css::ucb::XContentIdentifierMapping > & ContentIdentifierMapping + ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cacheddynamicresultsetstub.cxx b/ucb/source/cacher/cacheddynamicresultsetstub.cxx new file mode 100644 index 0000000000..8d46b6d823 --- /dev/null +++ b/ucb/source/cacher/cacheddynamicresultsetstub.cxx @@ -0,0 +1,235 @@ +/* -*- 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 "cacheddynamicresultsetstub.hxx" +#include "cachedcontentresultsetstub.hxx" +#include <com/sun/star/ucb/ContentResultSetCapability.hpp> +#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> +#include <osl/diagnose.h> +#include <ucbhelper/macros.hxx> +#include <cppuhelper/queryinterface.hxx> + +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + + +CachedDynamicResultSetStub::CachedDynamicResultSetStub( + Reference< XDynamicResultSet > const & xOrigin + , const Reference< XComponentContext > & rxContext ) + : DynamicResultSetWrapper( xOrigin, rxContext ) +{ + OSL_ENSURE( m_xContext.is(), "need Multiservicefactory to create stub" ); + impl_init(); +} + +CachedDynamicResultSetStub::~CachedDynamicResultSetStub() +{ + impl_deinit(); +} + +//virtual +void CachedDynamicResultSetStub + ::impl_InitResultSetOne( const Reference< XResultSet >& xResultSet ) +{ + DynamicResultSetWrapper::impl_InitResultSetOne( xResultSet ); + OSL_ENSURE( m_xSourceResultOne.is(), "need source resultset" ); + + Reference< XResultSet > xStub( + new CachedContentResultSetStub( m_xSourceResultOne ) ); + + std::unique_lock aGuard( m_aMutex ); + m_xMyResultOne = xStub; +} + +//virtual +void CachedDynamicResultSetStub + ::impl_InitResultSetTwo( const Reference< XResultSet >& xResultSet ) +{ + DynamicResultSetWrapper::impl_InitResultSetTwo( xResultSet ); + OSL_ENSURE( m_xSourceResultTwo.is(), "need source resultset" ); + + Reference< XResultSet > xStub( + new CachedContentResultSetStub( m_xSourceResultTwo ) ); + + std::unique_lock aGuard( m_aMutex ); + m_xMyResultTwo = xStub; +} + + +// XInterface methods. +void SAL_CALL CachedDynamicResultSetStub::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL CachedDynamicResultSetStub::release() + noexcept +{ + OWeakObject::release(); +} + +Any SAL_CALL CachedDynamicResultSetStub + ::queryInterface( const Type& rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + + Any aRet = DynamicResultSetWrapper::queryInterface( rType ); + if( aRet.hasValue() ) + return aRet; + + aRet = cppu::queryInterface( rType, + static_cast< XTypeProvider* >( this ) + , static_cast< XServiceInfo* >( this ) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +// XTypeProvider methods. + +//list all interfaces exclusive baseclasses +XTYPEPROVIDER_IMPL_5( CachedDynamicResultSetStub + , XTypeProvider + , XServiceInfo + , XDynamicResultSet + , XDynamicResultSetListener + , XSourceInitialization + ); + + +// XServiceInfo methods. + +OUString SAL_CALL CachedDynamicResultSetStub::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedDynamicResultSetStub"; +} + +sal_Bool SAL_CALL CachedDynamicResultSetStub::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL CachedDynamicResultSetStub::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedDynamicResultSetStub" }; +} + + + + + +CachedDynamicResultSetStubFactory::CachedDynamicResultSetStubFactory( + const Reference< XComponentContext > & rxContext ) +{ + m_xContext = rxContext; +} + +CachedDynamicResultSetStubFactory::~CachedDynamicResultSetStubFactory() +{ +} + +// CachedDynamicResultSetStubFactory XServiceInfo methods. + +OUString SAL_CALL CachedDynamicResultSetStubFactory::getImplementationName() +{ + return "com.sun.star.comp.ucb.CachedDynamicResultSetStubFactory"; +} +sal_Bool SAL_CALL CachedDynamicResultSetStubFactory::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} +css::uno::Sequence< OUString > SAL_CALL CachedDynamicResultSetStubFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.CachedDynamicResultSetStubFactory" }; +} + +// Service factory implementation. + + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_CachedDynamicResultSetStubFactory_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new CachedDynamicResultSetStubFactory(context)); +} + + +// CachedDynamicResultSetStubFactory XCachedDynamicResultSetStubFactory methods. + + +//virtual +Reference< XDynamicResultSet > SAL_CALL CachedDynamicResultSetStubFactory + ::createCachedDynamicResultSetStub( + const Reference< XDynamicResultSet > & Source ) +{ + Reference< XDynamicResultSet > xRet = new CachedDynamicResultSetStub( Source, m_xContext ); + return xRet; +} + +//virtual +void SAL_CALL CachedDynamicResultSetStubFactory + ::connectToCache( + const Reference< XDynamicResultSet > & Source + , const Reference< XDynamicResultSet > & TargetCache + , const Sequence< NumberedSortingInfo > & SortingInfo + , const Reference< XAnyCompareFactory > & CompareFactory + ) +{ + OSL_ENSURE( Source.is(), "a Source is needed" ); + OSL_ENSURE( TargetCache.is(), "a TargetCache is needed" ); + + Reference< XDynamicResultSet > xSource( Source ); + if( SortingInfo.hasElements() && + !( xSource->getCapabilities() & ContentResultSetCapability::SORTED ) + ) + { + Reference< XSortedDynamicResultSetFactory > xSortFactory; + try + { + xSortFactory = SortedDynamicResultSetFactory::create( m_xContext ); + } + catch ( Exception const & ) + { + } + + if( xSortFactory.is() ) + { + Reference< XDynamicResultSet > xSorted( + xSortFactory->createSortedDynamicResultSet( + Source, SortingInfo, CompareFactory ) ); + if( xSorted.is() ) + xSource = xSorted; + } + } + + Reference< XDynamicResultSet > xStub( + new CachedDynamicResultSetStub( xSource, m_xContext ) ); + + Reference< XSourceInitialization > xTarget( TargetCache, UNO_QUERY ); + OSL_ENSURE( xTarget.is(), "Target must have interface XSourceInitialization" ); + + xTarget->setSource( xStub ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/cacheddynamicresultsetstub.hxx b/ucb/source/cacher/cacheddynamicresultsetstub.hxx new file mode 100644 index 0000000000..b148efec9d --- /dev/null +++ b/ucb/source/cacher/cacheddynamicresultsetstub.hxx @@ -0,0 +1,101 @@ +/* -*- 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 . + */ + +#pragma once + +#include "dynamicresultsetwrapper.hxx" +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/ucb/XCachedDynamicResultSetStubFactory.hpp> +#include <cppuhelper/implbase.hxx> + + + +class CachedDynamicResultSetStub + : public DynamicResultSetWrapper + , public css::lang::XTypeProvider + , public css::lang::XServiceInfo +{ +protected: + virtual void + impl_InitResultSetOne( const css::uno::Reference< css::sdbc::XResultSet >& xResultSet ) override; + virtual void + impl_InitResultSetTwo( const css::uno::Reference< css::sdbc::XResultSet >& xResultSet ) override; + +public: + CachedDynamicResultSetStub( css::uno::Reference< css::ucb::XDynamicResultSet > const & xOrigin + , const css::uno::Reference< css::uno::XComponentContext > & rxContext ); + + virtual ~CachedDynamicResultSetStub() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + + +class CachedDynamicResultSetStubFactory final : + public cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::ucb::XCachedDynamicResultSetStubFactory> +{ + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +public: + + CachedDynamicResultSetStubFactory( + const css::uno::Reference< css::uno::XComponentContext > & rxContext); + + virtual ~CachedDynamicResultSetStubFactory() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XCachedDynamicResultSetStubFactory + + virtual css::uno::Reference< css::ucb::XDynamicResultSet > SAL_CALL + createCachedDynamicResultSetStub( + const css::uno::Reference< css::ucb::XDynamicResultSet > & Source ) override; + + + virtual void SAL_CALL connectToCache( + const css::uno::Reference< css::ucb::XDynamicResultSet > & Source + , const css::uno::Reference< css::ucb::XDynamicResultSet > & TargetCache + , const css::uno::Sequence< css::ucb::NumberedSortingInfo > & SortingInfo + , const css::uno::Reference< css::ucb::XAnyCompareFactory > & CompareFactory + ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/contentresultsetwrapper.cxx b/ucb/source/cacher/contentresultsetwrapper.cxx new file mode 100644 index 0000000000..d4b32024b9 --- /dev/null +++ b/ucb/source/cacher/contentresultsetwrapper.cxx @@ -0,0 +1,1207 @@ +/* -*- 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 "contentresultsetwrapper.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#include <rtl/ustring.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/queryinterface.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 comphelper; +using namespace cppu; + + + + +ContentResultSetWrapper::ContentResultSetWrapper( + Reference< XResultSet > const & xOrigin ) + : m_xResultSetOrigin( xOrigin ) + , m_nForwardOnly( 2 ) + , m_bDisposed( false ) + , m_bInDispose( false ) +{ + m_xMyListenerImpl = new ContentResultSetWrapperListener( this ); + + OSL_ENSURE( m_xResultSetOrigin.is(), "XResultSet is required" ); + + //!! call impl_init() at the end of constructor of derived class +}; + + +void ContentResultSetWrapper::impl_init_xRowOrigin(std::unique_lock<std::mutex>&) +{ + if(m_xRowOrigin.is()) + return; + + m_xRowOrigin.set(m_xResultSetOrigin, UNO_QUERY); + OSL_ENSURE( m_xRowOrigin.is(), "interface XRow is required" ); +} + +void ContentResultSetWrapper::impl_init_xContentAccessOrigin(std::unique_lock<std::mutex>&) +{ + if(m_xContentAccessOrigin.is()) + return; + + Reference< XContentAccess > xOrgig( m_xResultSetOrigin, UNO_QUERY ); + + m_xContentAccessOrigin = xOrgig; + OSL_ENSURE( m_xContentAccessOrigin.is(), "interface XContentAccess is required" ); +} + + +void ContentResultSetWrapper::impl_init_xPropertySetOrigin(std::unique_lock<std::mutex>&) +{ + if( m_xPropertySetOrigin.is() ) + return; + + Reference< XPropertySet > xOrig( m_xResultSetOrigin, UNO_QUERY ); + + m_xPropertySetOrigin = xOrig; + OSL_ENSURE( m_xPropertySetOrigin.is(), "interface XPropertySet is required" ); +} + +void ContentResultSetWrapper::impl_init() +{ + //call this at the end of constructor of derived class + + + //listen to disposing from Origin: + Reference< XComponent > xComponentOrigin( m_xResultSetOrigin, UNO_QUERY ); + OSL_ENSURE( xComponentOrigin.is(), "interface XComponent is required" ); + xComponentOrigin->addEventListener( static_cast< XPropertyChangeListener * >( m_xMyListenerImpl.get() ) ); +} + +ContentResultSetWrapper::~ContentResultSetWrapper() +{ + //call impl_deinit() at start of destructor of derived class +}; + +void ContentResultSetWrapper::impl_deinit() +{ + //call this at start of destructor of derived class + + m_xMyListenerImpl->impl_OwnerDies(); +} + +//virtual +void ContentResultSetWrapper::impl_initPropertySetInfo(std::unique_lock<std::mutex>& rGuard) +{ + if( m_xPropertySetInfo.is() ) + return; + + impl_init_xPropertySetOrigin(rGuard); + if( !m_xPropertySetOrigin.is() ) + return; + + Reference< XPropertySetInfo > xOrig = + m_xPropertySetOrigin->getPropertySetInfo(); + + m_xPropertySetInfo = xOrig; +} + +void ContentResultSetWrapper::impl_EnsureNotDisposed(std::unique_lock<std::mutex>& /*rGuard*/) +{ + if( m_bDisposed ) + throw DisposedException(); +} + +void ContentResultSetWrapper::impl_notifyPropertyChangeListeners( std::unique_lock<std::mutex>& rGuard, const PropertyChangeEvent& rEvt ) +{ + // Notify listeners interested especially in the changed property. + OInterfaceContainerHelper4<XPropertyChangeListener>* pContainer = + m_aPropertyChangeListeners.getContainer( rGuard, rEvt.PropertyName ); + if( pContainer ) + { + pContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvt ); + } + + // Notify listeners interested in all properties. + pContainer = m_aPropertyChangeListeners.getContainer( rGuard, OUString() ); + if( pContainer ) + { + pContainer->notifyEach( rGuard, &XPropertyChangeListener::propertyChange, rEvt ); + } +} + +void ContentResultSetWrapper::impl_notifyVetoableChangeListeners( std::unique_lock<std::mutex>& rGuard, const PropertyChangeEvent& rEvt ) +{ + // Notify listeners interested especially in the changed property. + OInterfaceContainerHelper4<XVetoableChangeListener>* pContainer = + m_aVetoableChangeListeners.getContainer( rGuard, rEvt.PropertyName ); + if( pContainer ) + { + pContainer->notifyEach( rGuard, &XVetoableChangeListener::vetoableChange, rEvt ); + } + + // Notify listeners interested in all properties. + pContainer = m_aVetoableChangeListeners.getContainer( rGuard, OUString() ); + if( pContainer ) + { + pContainer->notifyEach( rGuard, &XVetoableChangeListener::vetoableChange, rEvt ); + } +} + +bool ContentResultSetWrapper::impl_isForwardOnly(std::unique_lock<std::mutex>& /*rGuard*/) +{ + //m_nForwardOnly == 2 -> don't know + //m_nForwardOnly == 1 -> YES + //m_nForwardOnly == 0 -> NO + + //@todo replace this with lines in comment + m_nForwardOnly = 0; + return false; + + + /* + ReacquireableGuard aGuard( m_aMutex ); + if( m_nForwardOnly == 2 ) + { + aGuard.clear(); + if( !getPropertySetInfo().is() ) + { + aGuard.reacquire(); + m_nForwardOnly = 0; + return m_nForwardOnly; + } + aGuard.reacquire(); + + OUString aName("ResultSetType"); + //find out, if we are ForwardOnly and cache the value: + + impl_init_xPropertySetOrigin(); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + m_nForwardOnly = 0; + return m_nForwardOnly; + } + + aGuard.clear(); + Any aAny = m_xPropertySetOrigin->getPropertyValue( aName ); + + aGuard.reacquire(); + long nResultSetType; + if( ( aAny >>= nResultSetType ) && + ( nResultSetType == ResultSetType::FORWARD_ONLY ) ) + m_nForwardOnly = 1; + else + m_nForwardOnly = 0; + } + return m_nForwardOnly; + */ +} + + +// XInterface methods. + +css::uno::Any SAL_CALL ContentResultSetWrapper::queryInterface( const css::uno::Type & rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XComponent* >(this), + static_cast< XCloseable* >(this), + static_cast< XResultSetMetaDataSupplier* >(this), + static_cast< XPropertySet* >(this), + static_cast< XContentAccess* >(this), + static_cast< XResultSet* >(this), + static_cast< XRow* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XComponent methods. + +// virtual +void SAL_CALL ContentResultSetWrapper::dispose() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + bool isCleared = false; + if( m_bInDispose || m_bDisposed ) + return; + m_bInDispose = true; + + if( m_xPropertySetOrigin.is() ) + { + aGuard.unlock(); + isCleared = true; + try + { + m_xPropertySetOrigin->removePropertyChangeListener( + OUString(), static_cast< XPropertyChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + OSL_FAIL( "could not remove PropertyChangeListener" ); + } + try + { + m_xPropertySetOrigin->removeVetoableChangeListener( + OUString(), static_cast< XVetoableChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + OSL_FAIL( "could not remove VetoableChangeListener" ); + } + + Reference< XComponent > xComponentOrigin( m_xResultSetOrigin, UNO_QUERY ); + OSL_ENSURE( xComponentOrigin.is(), "interface XComponent is required" ); + xComponentOrigin->removeEventListener( static_cast< XPropertyChangeListener * >( m_xMyListenerImpl.get() ) ); + } + + if (isCleared) + aGuard.lock(); + if( m_aDisposeEventListeners.getLength(aGuard) ) + { + EventObject aEvt; + aEvt.Source = static_cast< XComponent * >( this ); + m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + } + + if( m_aPropertyChangeListeners.hasContainedTypes(aGuard) ) + { + EventObject aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + m_aPropertyChangeListeners.disposeAndClear( aGuard, aEvt ); + } + + if( m_aVetoableChangeListeners.hasContainedTypes(aGuard) ) + { + EventObject aEvt; + aEvt.Source = static_cast< XPropertySet * >( this ); + m_aVetoableChangeListeners.disposeAndClear( aGuard, aEvt ); + } + + m_bDisposed = true; + m_bInDispose = false; +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::addEventListener( const Reference< XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + + m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::removeEventListener( const Reference< XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +//XCloseable methods. + +//virtual +void SAL_CALL ContentResultSetWrapper::close() +{ + { + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + } + dispose(); +} + + +//XResultSetMetaDataSupplier methods. + +//virtual +Reference< XResultSetMetaData > SAL_CALL ContentResultSetWrapper::getMetaData() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xMetaDataFromOrigin.is() && m_xResultSetOrigin.is() ) + { + Reference< XResultSetMetaDataSupplier > xMetaDataSupplier( + m_xResultSetOrigin, UNO_QUERY ); + + if( xMetaDataSupplier.is() ) + { + aGuard.unlock(); + + Reference< XResultSetMetaData > xMetaData + = xMetaDataSupplier->getMetaData(); + + aGuard.lock(); + m_xMetaDataFromOrigin = xMetaData; + } + } + return m_xMetaDataFromOrigin; +} + + +// XPropertySet methods. + +// virtual +Reference< XPropertySetInfo > SAL_CALL ContentResultSetWrapper::getPropertySetInfo() +{ + std::unique_lock aGuard( m_aMutex ); + return getPropertySetInfoImpl(aGuard); +} + +// virtual +Reference< XPropertySetInfo > ContentResultSetWrapper::getPropertySetInfoImpl(std::unique_lock<std::mutex>& rGuard) +{ + impl_EnsureNotDisposed(rGuard); + if( m_xPropertySetInfo.is() ) + return m_xPropertySetInfo; + impl_initPropertySetInfo(rGuard); + return m_xPropertySetInfo; +} + +// virtual +void SAL_CALL ContentResultSetWrapper::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + std::unique_lock aGuard( m_aMutex ); + return setPropertyValueImpl(aGuard, rPropertyName, rValue); +} + +// virtual +void ContentResultSetWrapper::setPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, const OUString& rPropertyName, const Any& rValue ) +{ + impl_EnsureNotDisposed(rGuard); + impl_init_xPropertySetOrigin(rGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + m_xPropertySetOrigin->setPropertyValue( rPropertyName, rValue ); +} + + +// virtual +Any SAL_CALL ContentResultSetWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + impl_init_xPropertySetOrigin(aGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + return m_xPropertySetOrigin->getPropertyValue( rPropertyName ); +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + + if( !getPropertySetInfo().is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + + if( !aPropertyName.isEmpty() ) + { + m_xPropertySetInfo->getPropertyByName( aPropertyName ); + //throws UnknownPropertyException, if so + } + + bool bNeedRegister = !m_aPropertyChangeListeners.hasContainedTypes(aGuard); + m_aPropertyChangeListeners.addInterface( aGuard, aPropertyName, xListener ); + if( !bNeedRegister ) + return; + + impl_init_xPropertySetOrigin(aGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return; + } + try + { + m_xPropertySetOrigin->addPropertyChangeListener( + OUString(), static_cast< XPropertyChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + m_aPropertyChangeListeners.removeInterface( aGuard, aPropertyName, xListener ); + throw; + } +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::addVetoableChangeListener( const OUString& rPropertyName, const Reference< XVetoableChangeListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + + if( !getPropertySetInfo().is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw UnknownPropertyException(); + } + if( !rPropertyName.isEmpty() ) + { + m_xPropertySetInfo->getPropertyByName( rPropertyName ); + //throws UnknownPropertyException, if so + } + + bool bNeedRegister = !m_aVetoableChangeListeners.hasContainedTypes(aGuard); + m_aVetoableChangeListeners.addInterface( aGuard, rPropertyName, xListener ); + if( !bNeedRegister ) + return; + + impl_init_xPropertySetOrigin(aGuard); + { + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return; + } + } + try + { + m_xPropertySetOrigin->addVetoableChangeListener( + OUString(), static_cast< XVetoableChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + m_aVetoableChangeListeners.removeInterface( aGuard, rPropertyName, xListener ); + throw; + } +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::removePropertyChangeListener( const OUString& rPropertyName, const Reference< XPropertyChangeListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + + //noop, if no listener registered + if( !m_aPropertyChangeListeners.hasContainedTypes(aGuard) ) + return; + + OInterfaceContainerHelper4<XPropertyChangeListener>* pContainer = + m_aPropertyChangeListeners.getContainer( aGuard, rPropertyName ); + + if( !pContainer ) + { + if( !rPropertyName.isEmpty() ) + { + if( !getPropertySetInfo().is() ) + throw UnknownPropertyException(); + + m_xPropertySetInfo->getPropertyByName( rPropertyName ); + //throws UnknownPropertyException, if so + } + return; //the listener was not registered + } + + m_aPropertyChangeListeners.removeInterface( aGuard, rPropertyName, xListener ); + + if( m_aPropertyChangeListeners.hasContainedTypes(aGuard) ) + return; + + impl_init_xPropertySetOrigin(aGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return; + } + try + { + m_xPropertySetOrigin->removePropertyChangeListener( + OUString(), static_cast< XPropertyChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + OSL_FAIL( "could not remove PropertyChangeListener" ); + } +} + + +// virtual +void SAL_CALL ContentResultSetWrapper::removeVetoableChangeListener( const OUString& rPropertyName, const Reference< XVetoableChangeListener >& xListener ) +{ + std::unique_lock aGuard( m_aMutex ); + impl_EnsureNotDisposed(aGuard); + + //noop, if no listener registered + if( !m_aVetoableChangeListeners.hasContainedTypes(aGuard) ) + return; + OInterfaceContainerHelper4<XVetoableChangeListener>* pContainer = + m_aVetoableChangeListeners.getContainer( aGuard, rPropertyName ); + + if( !pContainer ) + { + if( !rPropertyName.isEmpty() ) + { + if( !getPropertySetInfo().is() ) + throw UnknownPropertyException(rPropertyName); + + m_xPropertySetInfo->getPropertyByName( rPropertyName ); + //throws UnknownPropertyException, if so + } + return; //the listener was not registered + } + + m_aVetoableChangeListeners.removeInterface( aGuard, rPropertyName, xListener ); + + if( m_aVetoableChangeListeners.hasContainedTypes(aGuard) ) + return; + + impl_init_xPropertySetOrigin(aGuard); + if( !m_xPropertySetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + return; + } + try + { + m_xPropertySetOrigin->removeVetoableChangeListener( + OUString(), static_cast< XVetoableChangeListener * >( m_xMyListenerImpl.get() ) ); + } + catch( Exception& ) + { + OSL_FAIL( "could not remove VetoableChangeListener" ); + } +} + + +// own methods. + + +//virtual, only called from ContentResultSetWrapperListener +void ContentResultSetWrapper::impl_disposing( const EventObject& ) +{ + std::unique_lock aGuard(m_aMutex); + + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + return; + + //release all references to the broadcaster: + m_xResultSetOrigin.clear(); + if(m_xRowOrigin.is()) + m_xRowOrigin.clear(); + if(m_xContentAccessOrigin.is()) + m_xContentAccessOrigin.clear(); + if(m_xPropertySetOrigin.is()) + m_xPropertySetOrigin.clear(); + m_xMetaDataFromOrigin.clear(); + if(m_xPropertySetInfo.is()) + m_xPropertySetInfo.clear(); +} + +//virtual, only called from ContentResultSetWrapperListener +void ContentResultSetWrapper::impl_propertyChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + + impl_EnsureNotDisposed(aGuard); + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + impl_notifyPropertyChangeListeners( aGuard, aEvt ); +} + +//virtual, only called from ContentResultSetWrapperListener +void ContentResultSetWrapper::impl_vetoableChange( const PropertyChangeEvent& rEvt ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + PropertyChangeEvent aEvt( rEvt ); + aEvt.Source = static_cast< XPropertySet * >( this ); + aEvt.Further = false; + + impl_notifyVetoableChangeListeners( aGuard, aEvt ); +} + + +// XContentAccess methods. ( -- position dependent ) + + +// virtual +OUString SAL_CALL ContentResultSetWrapper::queryContentIdentifierString() +{ + std::unique_lock aGuard(m_aMutex); + return queryContentIdentifierStringImpl(aGuard); +} +// virtual +OUString ContentResultSetWrapper::queryContentIdentifierStringImpl(std::unique_lock<std::mutex>& rGuard) +{ + impl_EnsureNotDisposed(rGuard); + impl_init_xContentAccessOrigin(rGuard); + if( !m_xContentAccessOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xContentAccessOrigin->queryContentIdentifierString(); +} + + +// virtual +Reference< XContentIdentifier > SAL_CALL ContentResultSetWrapper::queryContentIdentifier() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xContentAccessOrigin(aGuard); + if( !m_xContentAccessOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xContentAccessOrigin->queryContentIdentifier(); +} + + +// virtual +Reference< XContent > SAL_CALL ContentResultSetWrapper::queryContent() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xContentAccessOrigin(aGuard); + if( !m_xContentAccessOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xContentAccessOrigin->queryContent(); +} + + +// XResultSet methods. + +//virtual + +sal_Bool SAL_CALL ContentResultSetWrapper::next() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->next(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::previous() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->previous(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::absolute( sal_Int32 row ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->absolute( row ); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::relative( sal_Int32 rows ) +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->relative( rows ); +} + + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::first() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->first(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::last() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->last(); +} + +//virtual +void SAL_CALL ContentResultSetWrapper::beforeFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + m_xResultSetOrigin->beforeFirst(); +} + +//virtual +void SAL_CALL ContentResultSetWrapper::afterLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + m_xResultSetOrigin->afterLast(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::isAfterLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->isAfterLast(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::isBeforeFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->isBeforeFirst(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::isFirst() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->isFirst(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::isLast() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->isLast(); +} + + +//virtual +sal_Int32 SAL_CALL ContentResultSetWrapper::getRow() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->getRow(); +} + +//virtual +void SAL_CALL ContentResultSetWrapper::refreshRow() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + m_xResultSetOrigin->refreshRow(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::rowUpdated() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->rowUpdated(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::rowInserted() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->rowInserted(); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::rowDeleted() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + + if( !m_xResultSetOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xResultSetOrigin->rowDeleted(); +} + +//virtual +Reference< XInterface > SAL_CALL ContentResultSetWrapper::getStatement() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + //@todo ?return anything + return Reference< XInterface >(); +} + + +// XRow methods. + + +void ContentResultSetWrapper::verifyGet() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xRowOrigin(aGuard); + if( !m_xRowOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::wasNull() +{ + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xRowOrigin(aGuard); + if( !m_xRowOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xRowOrigin->wasNull(); +} + +//virtual +OUString SAL_CALL ContentResultSetWrapper::getString( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getString( columnIndex ); +} + +//virtual +sal_Bool SAL_CALL ContentResultSetWrapper::getBoolean( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getBoolean( columnIndex ); +} + +//virtual +sal_Int8 SAL_CALL ContentResultSetWrapper::getByte( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getByte( columnIndex ); +} + +//virtual +sal_Int16 SAL_CALL ContentResultSetWrapper::getShort( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getShort( columnIndex ); +} + +//virtual +sal_Int32 SAL_CALL ContentResultSetWrapper::getInt( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getInt( columnIndex ); +} + +//virtual +sal_Int64 SAL_CALL ContentResultSetWrapper::getLong( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getLong( columnIndex ); +} + +//virtual +float SAL_CALL ContentResultSetWrapper::getFloat( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getFloat( columnIndex ); +} + +//virtual +double SAL_CALL ContentResultSetWrapper::getDouble( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getDouble( columnIndex ); +} + +//virtual +Sequence< sal_Int8 > SAL_CALL ContentResultSetWrapper::getBytes( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getBytes( columnIndex ); +} + +//virtual +Date SAL_CALL ContentResultSetWrapper::getDate( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getDate( columnIndex ); +} + +//virtual +Time SAL_CALL ContentResultSetWrapper::getTime( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getTime( columnIndex ); +} + +//virtual +DateTime SAL_CALL ContentResultSetWrapper::getTimestamp( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getTimestamp( columnIndex ); +} + +//virtual +Reference< css::io::XInputStream > SAL_CALL ContentResultSetWrapper::getBinaryStream( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getBinaryStream( columnIndex ); +} + +//virtual +Reference< css::io::XInputStream > SAL_CALL ContentResultSetWrapper::getCharacterStream( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getCharacterStream( columnIndex ); +} + +//virtual +Any SAL_CALL ContentResultSetWrapper::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap ) +{ + //if you change this macro please pay attention to + //define XROW_GETXXX, where this is similar implemented + + std::unique_lock aGuard(m_aMutex); + impl_EnsureNotDisposed(aGuard); + impl_init_xRowOrigin(aGuard); + if( !m_xRowOrigin.is() ) + { + OSL_FAIL( "broadcaster was disposed already" ); + throw RuntimeException(); + } + return m_xRowOrigin->getObject( columnIndex, typeMap ); +} + +//virtual +Reference< XRef > SAL_CALL ContentResultSetWrapper::getRef( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getRef( columnIndex ); +} + +//virtual +Reference< XBlob > SAL_CALL ContentResultSetWrapper::getBlob( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getBlob( columnIndex ); +} + +//virtual +Reference< XClob > SAL_CALL ContentResultSetWrapper::getClob( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getClob( columnIndex ); +} + +//virtual +Reference< XArray > SAL_CALL ContentResultSetWrapper::getArray( sal_Int32 columnIndex ) +{ + verifyGet(); + return m_xRowOrigin->getArray( columnIndex ); +} + + + + +ContentResultSetWrapperListener::ContentResultSetWrapperListener( + ContentResultSetWrapper* pOwner ) + : m_pOwner( pOwner ) +{ +} + +ContentResultSetWrapperListener::~ContentResultSetWrapperListener() +{ +} + + +// XInterface methods. +void SAL_CALL ContentResultSetWrapperListener::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL ContentResultSetWrapperListener::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL ContentResultSetWrapperListener::queryInterface( const css::uno::Type & rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XEventListener * >( + static_cast< XPropertyChangeListener * >(this)), + static_cast< XPropertyChangeListener* >(this), + static_cast< XVetoableChangeListener* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +//XEventListener methods. + + +//virtual +void SAL_CALL ContentResultSetWrapperListener::disposing( const EventObject& rEventObject ) +{ + if( m_pOwner ) + m_pOwner->impl_disposing( rEventObject ); +} + + +//XPropertyChangeListener methods. + + +//virtual +void SAL_CALL ContentResultSetWrapperListener::propertyChange( const PropertyChangeEvent& rEvt ) +{ + if( m_pOwner ) + m_pOwner->impl_propertyChange( rEvt ); +} + + +//XVetoableChangeListener methods. + +//virtual +void SAL_CALL ContentResultSetWrapperListener::vetoableChange( const PropertyChangeEvent& rEvt ) +{ + if( m_pOwner ) + m_pOwner->impl_vetoableChange( rEvt ); +} + +void ContentResultSetWrapperListener::impl_OwnerDies() +{ + m_pOwner = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/contentresultsetwrapper.hxx b/ucb/source/cacher/contentresultsetwrapper.hxx new file mode 100644 index 0000000000..372779d6e3 --- /dev/null +++ b/ucb/source/cacher/contentresultsetwrapper.hxx @@ -0,0 +1,384 @@ +/* -*- 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 . + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include <rtl/ref.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/multiinterfacecontainer4.hxx> +#include <memory> + + +class ContentResultSetWrapperListener; +class ContentResultSetWrapper + : public cppu::OWeakObject + , public css::lang::XComponent + , public css::sdbc::XCloseable + , public css::sdbc::XResultSetMetaDataSupplier + , public css::beans::XPropertySet + , public css::ucb::XContentAccess + , public css::sdbc::XResultSet + , public css::sdbc::XRow +{ +protected: + typedef comphelper::OMultiTypeInterfaceContainerHelperVar4<OUString, css::beans::XPropertyChangeListener> + PropertyChangeListenerContainer_Impl; + typedef comphelper::OMultiTypeInterfaceContainerHelperVar4<OUString, css::beans::XVetoableChangeListener> + VetoableChangeListenerContainer_Impl; + + //members + + //my Mutex + std::mutex m_aMutex; + + //different Interfaces from Origin: + css::uno::Reference< css::sdbc::XResultSet > + m_xResultSetOrigin; + css::uno::Reference< css::sdbc::XRow > + m_xRowOrigin; //XRow-interface from m_xOrigin + //!! call impl_init_xRowOrigin() bevor you access this member + css::uno::Reference< css::ucb::XContentAccess > + m_xContentAccessOrigin; //XContentAccess-interface from m_xOrigin + //!! call impl_init_xContentAccessOrigin() bevor you access this member + css::uno::Reference< css::beans::XPropertySet > + m_xPropertySetOrigin; //XPropertySet-interface from m_xOrigin + //!! call impl_init_xPropertySetOrigin() bevor you access this member + + css::uno::Reference< css::beans::XPropertySetInfo > + m_xPropertySetInfo; + //call impl_initPropertySetInfo() bevor you access this member + + sal_Int32 m_nForwardOnly; + +private: + rtl::Reference<ContentResultSetWrapperListener> + m_xMyListenerImpl; + + css::uno::Reference< css::sdbc::XResultSetMetaData > + m_xMetaDataFromOrigin; //XResultSetMetaData from m_xOrigin + + //management of listeners + bool m_bDisposed; ///Dispose call ready. + bool m_bInDispose;///In dispose call + comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> + m_aDisposeEventListeners; + PropertyChangeListenerContainer_Impl + m_aPropertyChangeListeners; + VetoableChangeListenerContainer_Impl + m_aVetoableChangeListeners; + + + //methods: +private: + void verifyGet(); + +protected: + + + ContentResultSetWrapper( css::uno::Reference< css::sdbc::XResultSet > const & xOrigin ); + + virtual ~ContentResultSetWrapper() override; + + void impl_init(); + void impl_deinit(); + + //-- + + void impl_init_xRowOrigin(std::unique_lock<std::mutex>&); + void impl_init_xContentAccessOrigin(std::unique_lock<std::mutex>&); + void impl_init_xPropertySetOrigin(std::unique_lock<std::mutex>&); + + //-- + + virtual void impl_initPropertySetInfo(std::unique_lock<std::mutex>& rGuard); //helping XPropertySet + + /// @throws css::lang::DisposedException + /// @throws css::uno::RuntimeException + void + impl_EnsureNotDisposed(std::unique_lock<std::mutex>& rGuard); + + void + impl_notifyPropertyChangeListeners( + std::unique_lock<std::mutex>& rGuard, + const css::beans::PropertyChangeEvent& rEvt ); + + /// @throws css::beans::PropertyVetoException + /// @throws css::uno::RuntimeException + void + impl_notifyVetoableChangeListeners( + std::unique_lock<std::mutex>& rGuard, + const css::beans::PropertyChangeEvent& rEvt ); + + bool impl_isForwardOnly(std::unique_lock<std::mutex>& rGuard); + +public: + + + // XInterface + + virtual css::uno::Any SAL_CALL + queryInterface( const css::uno::Type & rType ) override; + + + // XComponent + + virtual void SAL_CALL + dispose() override final; + + virtual void SAL_CALL + addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override; + + + //XCloseable + + virtual void SAL_CALL + close() override; + + + //XResultSetMetaDataSupplier + + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL + getMetaData() override; + + + // XPropertySet + + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override final; + css::uno::Reference< css::beans::XPropertySetInfo > + getPropertySetInfoImpl(std::unique_lock<std::mutex>& rGuard); + + virtual void SAL_CALL + setPropertyValue( const OUString& aPropertyName, + const css::uno::Any& aValue ) final override; + virtual void + setPropertyValueImpl( std::unique_lock<std::mutex>& rGuard, const OUString& aPropertyName, + const css::uno::Any& aValue ); + + virtual css::uno::Any SAL_CALL + getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL + addPropertyChangeListener( const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + + virtual void SAL_CALL + removePropertyChangeListener( const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual void SAL_CALL + addVetoableChangeListener( const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + virtual void SAL_CALL + removeVetoableChangeListener( const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + + // own methods + + /// @throws css::uno::RuntimeException + virtual void + impl_disposing( const css::lang::EventObject& Source ); + + /// @throws css::uno::RuntimeException + virtual void + impl_propertyChange( const css::beans::PropertyChangeEvent& evt ); + + /// @throws css::beans::PropertyVetoException + /// @throws css::uno::RuntimeException + virtual void + impl_vetoableChange( const css::beans::PropertyChangeEvent& aEvent ); + + + // XContentAccess + + virtual OUString SAL_CALL + queryContentIdentifierString() override final; + virtual OUString + queryContentIdentifierStringImpl(std::unique_lock<std::mutex>& rGuard); + + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL + queryContentIdentifier() override; + + virtual css::uno::Reference< css::ucb::XContent > SAL_CALL + queryContent() override; + + + // XResultSet + + virtual sal_Bool SAL_CALL + next() override; + virtual sal_Bool SAL_CALL + isBeforeFirst() override; + virtual sal_Bool SAL_CALL + isAfterLast() override; + virtual sal_Bool SAL_CALL + isFirst() override; + virtual sal_Bool SAL_CALL + isLast() override; + virtual void SAL_CALL + beforeFirst() override; + virtual void SAL_CALL + afterLast() override; + virtual sal_Bool SAL_CALL + first() override; + virtual sal_Bool SAL_CALL + last() override; + virtual sal_Int32 SAL_CALL + getRow() override; + virtual sal_Bool SAL_CALL + absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL + relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL + previous() override; + virtual void SAL_CALL + refreshRow() override; + virtual sal_Bool SAL_CALL + rowUpdated() override; + virtual sal_Bool SAL_CALL + rowInserted() override; + virtual sal_Bool SAL_CALL + rowDeleted() override; + virtual css::uno::Reference< + css::uno::XInterface > SAL_CALL + getStatement() override; + + + // XRow + + virtual sal_Bool SAL_CALL + wasNull() override; + + virtual OUString SAL_CALL + getString( sal_Int32 columnIndex ) override; + + virtual sal_Bool SAL_CALL + getBoolean( sal_Int32 columnIndex ) override; + + virtual sal_Int8 SAL_CALL + getByte( sal_Int32 columnIndex ) override; + + virtual sal_Int16 SAL_CALL + getShort( sal_Int32 columnIndex ) override; + + virtual sal_Int32 SAL_CALL + getInt( sal_Int32 columnIndex ) override; + + virtual sal_Int64 SAL_CALL + getLong( sal_Int32 columnIndex ) override; + + virtual float SAL_CALL + getFloat( sal_Int32 columnIndex ) override; + + virtual double SAL_CALL + getDouble( sal_Int32 columnIndex ) override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes( sal_Int32 columnIndex ) override; + + virtual css::util::Date SAL_CALL + getDate( sal_Int32 columnIndex ) override; + + virtual css::util::Time SAL_CALL + getTime( sal_Int32 columnIndex ) override; + + virtual css::util::DateTime SAL_CALL + getTimestamp( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Any SAL_CALL + getObject( sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL + getRef( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL + getBlob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL + getClob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL + getArray( sal_Int32 columnIndex ) override; +}; + + +class ContentResultSetWrapperListener + : public cppu::OWeakObject + , public css::beans::XPropertyChangeListener + , public css::beans::XVetoableChangeListener +{ + ContentResultSetWrapper* m_pOwner; + +public: + ContentResultSetWrapperListener( ContentResultSetWrapper* pOwner ); + + virtual ~ContentResultSetWrapperListener() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + //XEventListener + + virtual void SAL_CALL + disposing( const css::lang::EventObject& Source ) override; + + + //XPropertyChangeListener + + virtual void SAL_CALL + propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + + //XVetoableChangeListener + + virtual void SAL_CALL + vetoableChange( const css::beans::PropertyChangeEvent& aEvent ) override; + + + // own methods: + void impl_OwnerDies(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/dynamicresultsetwrapper.cxx b/ucb/source/cacher/dynamicresultsetwrapper.cxx new file mode 100644 index 0000000000..db881dad49 --- /dev/null +++ b/ucb/source/cacher/dynamicresultsetwrapper.cxx @@ -0,0 +1,478 @@ +/* -*- 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 "dynamicresultsetwrapper.hxx" +#include <cppuhelper/queryinterface.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/ucb/AlreadyInitializedException.hpp> +#include <com/sun/star/ucb/ListActionType.hpp> +#include <com/sun/star/ucb/ListenerAlreadySetException.hpp> +#include <com/sun/star/ucb/ServiceNotFoundException.hpp> +#include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp> +#include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp> + +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 comphelper; + + + + +DynamicResultSetWrapper::DynamicResultSetWrapper( + Reference< XDynamicResultSet > const & xOrigin + , const Reference< XComponentContext > & rxContext ) + + : m_bDisposed( false ) + , m_bInDispose( false ) + , m_xContext( rxContext ) + , m_bStatic( false ) + , m_bGotWelcome( false ) + , m_xSource( xOrigin ) + // , m_xSourceResultCurrent( NULL ) + // , m_bUseOne( NULL ) +{ + m_xMyListenerImpl = new DynamicResultSetWrapperListener( this ); + //call impl_init() at the end of constructor of derived class +}; + +void DynamicResultSetWrapper::impl_init() +{ + //call this at the end of constructor of derived class + + + Reference< XDynamicResultSet > xSource; + { + std::unique_lock aGuard( m_aMutex ); + xSource = m_xSource; + m_xSource = nullptr; + } + if( xSource.is() ) + setSource( xSource ); +} + +DynamicResultSetWrapper::~DynamicResultSetWrapper() +{ + //call impl_deinit() at start of destructor of derived class +}; + +void DynamicResultSetWrapper::impl_deinit() +{ + //call this at start of destructor of derived class + + m_xMyListenerImpl->impl_OwnerDies(); +} + +void DynamicResultSetWrapper::impl_EnsureNotDisposed() +{ + std::unique_lock aGuard( m_aMutex ); + if( m_bDisposed ) + throw DisposedException(); +} + +//virtual +void DynamicResultSetWrapper::impl_InitResultSetOne( const Reference< XResultSet >& xResultSet ) +{ + std::unique_lock aGuard( m_aMutex ); + OSL_ENSURE( !m_xSourceResultOne.is(), "Source ResultSet One is set already" ); + m_xSourceResultOne = xResultSet; + m_xMyResultOne = xResultSet; +} + +//virtual +void DynamicResultSetWrapper::impl_InitResultSetTwo( const Reference< XResultSet >& xResultSet ) +{ + std::unique_lock aGuard( m_aMutex ); + OSL_ENSURE( !m_xSourceResultTwo.is(), "Source ResultSet Two is set already" ); + m_xSourceResultTwo = xResultSet; + m_xMyResultTwo = xResultSet; +} + +// XInterface methods. +css::uno::Any SAL_CALL DynamicResultSetWrapper::queryInterface( const css::uno::Type & rType ) +{ + //list all interfaces inclusive baseclasses of interfaces + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XComponent* >(this), //base of XDynamicResultSet + static_cast< XDynamicResultSet* >(this), + static_cast< XSourceInitialization* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XComponent methods. + +// virtual +void SAL_CALL DynamicResultSetWrapper::dispose() +{ + impl_EnsureNotDisposed(); + + std::unique_lock aGuard( m_aMutex ); + Reference< XComponent > xSourceComponent; + if( m_bInDispose || m_bDisposed ) + return; + m_bInDispose = true; + + xSourceComponent = m_xSource; + + if( m_aDisposeEventListeners.getLength(aGuard) ) + { + EventObject aEvt; + aEvt.Source = static_cast< XComponent * >( this ); + m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + } + + /* //@todo ?? ( only if java collection needs to long ) + if( xSourceComponent.is() ) + xSourceComponent->dispose(); + */ + + m_bDisposed = true; + m_bInDispose = false; +} + + +// virtual +void SAL_CALL DynamicResultSetWrapper::addEventListener( const Reference< XEventListener >& Listener ) +{ + impl_EnsureNotDisposed(); + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +// virtual +void SAL_CALL DynamicResultSetWrapper::removeEventListener( const Reference< XEventListener >& Listener ) +{ + impl_EnsureNotDisposed(); + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +// own methods + + +//virtual +void DynamicResultSetWrapper::impl_disposing( const EventObject& ) +{ + impl_EnsureNotDisposed(); + + std::unique_lock aGuard( m_aMutex ); + + if( !m_xSource.is() ) + return; + + //release all references to the broadcaster: + m_xSource.clear(); + m_xSourceResultOne.clear();//?? or only when not static?? + m_xSourceResultTwo.clear();//?? + //@todo m_xMyResultOne.clear(); ??? + //@todo m_xMyResultTwo.clear(); ??? +} + +//virtual +void DynamicResultSetWrapper::impl_notify( const ListEvent& Changes ) +{ + impl_EnsureNotDisposed(); + //@todo + /* + <p>The Listener is allowed to blockade this call, until he really want to go + to the new version. The only situation, where the listener has to return the + update call at once is, while he disposes his broadcaster or while he is + removing himself as listener (otherwise you deadlock)!!! + */ + // handle the actions in the list + + ListEvent aNewEvent; + aNewEvent.Source = static_cast< XDynamicResultSet * >( this ); + aNewEvent.Changes = Changes.Changes; + + { + std::unique_lock aGuard( m_aMutex ); + for( ListAction& rAction : asNonConstRange(aNewEvent.Changes) ) + { + if (m_bGotWelcome) + break; + + switch( rAction.ListActionType ) + { + case ListActionType::WELCOME: + { + WelcomeDynamicResultSetStruct aWelcome; + if( rAction.ActionInfo >>= aWelcome ) + { + impl_InitResultSetOne( aWelcome.Old ); + impl_InitResultSetTwo( aWelcome.New ); + m_bGotWelcome = true; + + aWelcome.Old = m_xMyResultOne; + aWelcome.New = m_xMyResultTwo; + + rAction.ActionInfo <<= aWelcome; + } + else + { + OSL_FAIL( "ListActionType was WELCOME but ActionInfo didn't contain a WelcomeDynamicResultSetStruct" ); + //throw RuntimeException(); + } + break; + } + } + } + OSL_ENSURE( m_bGotWelcome, "first notification was without WELCOME" ); + } + + if( !m_xListener.is() ) + m_aListenerSet.wait(); + m_xListener->notify( aNewEvent ); + + /* + m_bUseOne = !m_bUseOne; + if( m_bUseOne ) + m_xSourceResultCurrent = m_xSourceResultOne; + else + m_xSourceResultCurrent = m_xSourceResultTwo; + */ +} + + +// XSourceInitialization + +//virtual +void SAL_CALL DynamicResultSetWrapper::setSource( const Reference< XInterface > & Source ) +{ + impl_EnsureNotDisposed(); + { + std::unique_lock aGuard( m_aMutex ); + if( m_xSource.is() ) + { + throw AlreadyInitializedException(); + } + } + + Reference< XDynamicResultSet > xSourceDynamic( Source, UNO_QUERY ); + OSL_ENSURE( xSourceDynamic.is(), + "the given source is not of required type XDynamicResultSet" ); + + Reference< XDynamicResultSetListener > xListener; + Reference< XDynamicResultSetListener > xMyListenerImpl; + + bool bStatic = false; + { + std::unique_lock aGuard( m_aMutex ); + m_xSource = xSourceDynamic; + xListener = m_xListener; + bStatic = m_bStatic; + xMyListenerImpl = m_xMyListenerImpl.get(); + } + if( xListener.is() ) + xSourceDynamic->setListener( m_xMyListenerImpl ); + else if( bStatic ) + { + Reference< XComponent > xSourceComponent( Source, UNO_QUERY ); + xSourceComponent->addEventListener( xMyListenerImpl ); + } + m_aSourceSet.set(); +} + + +// XDynamicResultSet + +//virtual +Reference< XResultSet > SAL_CALL DynamicResultSetWrapper::getStaticResultSet() +{ + impl_EnsureNotDisposed(); + + Reference< XDynamicResultSet > xSource; + Reference< XEventListener > xMyListenerImpl; + { + std::unique_lock aGuard( m_aMutex ); + if( m_xListener.is() ) + throw ListenerAlreadySetException(); + + xSource = m_xSource; + m_bStatic = true; + xMyListenerImpl = m_xMyListenerImpl.get(); + } + + if( xSource.is() ) + { + xSource->addEventListener( xMyListenerImpl ); + } + if( !xSource.is() ) + m_aSourceSet.wait(); + + + Reference< XResultSet > xResultSet = xSource->getStaticResultSet(); + impl_InitResultSetOne( xResultSet ); + return m_xMyResultOne; +} + +//virtual +void SAL_CALL DynamicResultSetWrapper::setListener( const Reference< XDynamicResultSetListener > & Listener ) +{ + impl_EnsureNotDisposed(); + + Reference< XDynamicResultSet > xSource; + Reference< XDynamicResultSetListener > xMyListenerImpl; + { + std::unique_lock aGuard( m_aMutex ); + if( m_xListener.is() ) + throw ListenerAlreadySetException(); + if( m_bStatic ) + throw ListenerAlreadySetException(); + + m_xListener = Listener; + addEventListener( Listener ); + + xSource = m_xSource; + xMyListenerImpl = m_xMyListenerImpl.get(); + } + if ( xSource.is() ) + xSource->setListener( xMyListenerImpl ); + + m_aListenerSet.set(); +} + +//virtual +void SAL_CALL DynamicResultSetWrapper::connectToCache( const Reference< XDynamicResultSet > & xCache ) +{ + impl_EnsureNotDisposed(); + + if( m_xListener.is() ) + throw ListenerAlreadySetException(); + if( m_bStatic ) + throw ListenerAlreadySetException(); + + Reference< XSourceInitialization > xTarget( xCache, UNO_QUERY ); + OSL_ENSURE( xTarget.is(), "The given Target doesn't have the required interface 'XSourceInitialization'" ); + if( xTarget.is() && m_xContext.is() ) + { + //@todo m_aSourceSet.wait();? + + Reference< XCachedDynamicResultSetStubFactory > xStubFactory; + try + { + xStubFactory = CachedDynamicResultSetStubFactory::create( m_xContext ); + } + catch ( Exception const & ) + { + } + + if( xStubFactory.is() ) + { + xStubFactory->connectToCache( + this, xCache, Sequence< NumberedSortingInfo > (), nullptr ); + return; + } + } + OSL_FAIL( "could not connect to cache" ); + throw ServiceNotFoundException(); +} + +//virtual +sal_Int16 SAL_CALL DynamicResultSetWrapper::getCapabilities() +{ + impl_EnsureNotDisposed(); + + m_aSourceSet.wait(); + Reference< XDynamicResultSet > xSource; + { + std::unique_lock aGuard( m_aMutex ); + xSource = m_xSource; + } + return xSource->getCapabilities(); +} + + + + +DynamicResultSetWrapperListener::DynamicResultSetWrapperListener( + DynamicResultSetWrapper* pOwner ) + : m_pOwner( pOwner ) +{ + +} + +DynamicResultSetWrapperListener::~DynamicResultSetWrapperListener() +{ + +} + + +// XInterface methods. + +void SAL_CALL DynamicResultSetWrapperListener::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL DynamicResultSetWrapperListener::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL DynamicResultSetWrapperListener::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XDynamicResultSetListener* >(this), + static_cast< XEventListener* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XDynamicResultSetListener methods: + +//virtual +void SAL_CALL DynamicResultSetWrapperListener::disposing( const EventObject& rEventObject ) +{ + std::unique_lock aGuard( m_aMutex ); + + if( m_pOwner ) + m_pOwner->impl_disposing( rEventObject ); +} + +//virtual +void SAL_CALL DynamicResultSetWrapperListener::notify( const ListEvent& Changes ) +{ + std::unique_lock aGuard( m_aMutex ); + + if( m_pOwner ) + m_pOwner->impl_notify( Changes ); +} + + +// own methods: + + +void DynamicResultSetWrapperListener::impl_OwnerDies() +{ + std::unique_lock aGuard( m_aMutex ); + + m_pOwner = nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/cacher/dynamicresultsetwrapper.hxx b/ucb/source/cacher/dynamicresultsetwrapper.hxx new file mode 100644 index 0000000000..a7917506d8 --- /dev/null +++ b/ucb/source/cacher/dynamicresultsetwrapper.hxx @@ -0,0 +1,182 @@ +/* -*- 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 . + */ + +#pragma once + +#include <mutex> +#include <osl/conditn.hxx> +#include <cppuhelper/weak.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XSourceInitialization.hpp> +#include <com/sun/star/ucb/XDynamicResultSetListener.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <rtl/ref.hxx> + +#include <memory> + +class DynamicResultSetWrapperListener; +class DynamicResultSetWrapper + : public cppu::OWeakObject + , public css::ucb::XDynamicResultSet + , public css::ucb::XSourceInitialization +{ +private: + //management of listeners + bool m_bDisposed; ///Dispose call ready. + bool m_bInDispose;///In dispose call + comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> + m_aDisposeEventListeners; +protected: + rtl::Reference<DynamicResultSetWrapperListener> + m_xMyListenerImpl; + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + std::mutex m_aMutex; + bool m_bStatic; + bool m_bGotWelcome; + + //different Interfaces from Origin: + css::uno::Reference< css::ucb::XDynamicResultSet > + m_xSource; + css::uno::Reference< css::sdbc::XResultSet > + m_xSourceResultOne; + css::uno::Reference< css::sdbc::XResultSet > + m_xSourceResultTwo; + + css::uno::Reference< css::sdbc::XResultSet > + m_xMyResultOne; + css::uno::Reference< css::sdbc::XResultSet > + m_xMyResultTwo; + + css::uno::Reference< css::ucb::XDynamicResultSetListener > + m_xListener; + + osl::Condition m_aSourceSet; + osl::Condition m_aListenerSet; + +protected: + void impl_init(); + void impl_deinit(); + /// @throws css::lang::DisposedException + /// @throws css::uno::RuntimeException + void + impl_EnsureNotDisposed(); + + virtual void + impl_InitResultSetOne( const css::uno::Reference< + css::sdbc::XResultSet >& xResultSet ); + virtual void + impl_InitResultSetTwo( const css::uno::Reference< + css::sdbc::XResultSet >& xResultSet ); + +public: + + DynamicResultSetWrapper( + css::uno::Reference< css::ucb::XDynamicResultSet > const & xOrigin + , const css::uno::Reference< css::uno::XComponentContext > & rxContext ); + + virtual ~DynamicResultSetWrapper() override; + + + // XInterface + virtual css::uno::Any SAL_CALL + queryInterface( const css::uno::Type & rType ) override; + + + // XDynamicResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getStaticResultSet() override; + + virtual void SAL_CALL + setListener( const css::uno::Reference< css::ucb::XDynamicResultSetListener > & Listener ) override; + + virtual void SAL_CALL + connectToCache( const css::uno::Reference< css::ucb::XDynamicResultSet > & xCache ) override; + + virtual sal_Int16 SAL_CALL + getCapabilities() override; + + + // XComponent ( base of XDynamicResultSet ) + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override; + + + // XSourceInitialization + + virtual void SAL_CALL + setSource( const css::uno::Reference< css::uno::XInterface > & Source ) override; + + + // own methods: + /// @throws css::uno::RuntimeException + virtual void + impl_disposing( const css::lang::EventObject& Source ); + + /// @throws css::uno::RuntimeException + void + impl_notify( const css::ucb::ListEvent& Changes ); +}; + + +class DynamicResultSetWrapperListener + : public cppu::OWeakObject + , public css::ucb::XDynamicResultSetListener +{ + DynamicResultSetWrapper* m_pOwner; + std::mutex m_aMutex; + +public: + DynamicResultSetWrapperListener( DynamicResultSetWrapper* pOwner ); + + virtual ~DynamicResultSetWrapperListener() override; + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XEventListener ( base of XDynamicResultSetListener ) + + virtual void SAL_CALL + disposing( const css::lang::EventObject& Source ) override; + + // XDynamicResultSetListener + virtual void SAL_CALL + notify( const css::ucb::ListEvent& Changes ) override; + + + // own methods: + void impl_OwnerDies(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |