summaryrefslogtreecommitdiffstats
path: root/ucb/source/cacher
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /ucb/source/cacher
parentInitial commit. (diff)
downloadlibreoffice-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.component38
-rw-r--r--ucb/source/cacher/cachedcontentresultset.cxx2037
-rw-r--r--ucb/source/cacher/cachedcontentresultset.hxx386
-rw-r--r--ucb/source/cacher/cachedcontentresultsetstub.cxx551
-rw-r--r--ucb/source/cacher/cachedcontentresultsetstub.hxx168
-rw-r--r--ucb/source/cacher/cacheddynamicresultset.cxx200
-rw-r--r--ucb/source/cacher/cacheddynamicresultset.hxx104
-rw-r--r--ucb/source/cacher/cacheddynamicresultsetstub.cxx235
-rw-r--r--ucb/source/cacher/cacheddynamicresultsetstub.hxx101
-rw-r--r--ucb/source/cacher/contentresultsetwrapper.cxx1207
-rw-r--r--ucb/source/cacher/contentresultsetwrapper.hxx384
-rw-r--r--ucb/source/cacher/dynamicresultsetwrapper.cxx478
-rw-r--r--ucb/source/cacher/dynamicresultsetwrapper.hxx182
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: */