1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include "cachedcontentresultsetstub.hxx"
22 #include <com/sun/star/sdbc/FetchDirection.hpp>
23 #include <com/sun/star/sdbc/SQLException.hpp>
24 #include <com/sun/star/ucb/FetchError.hpp>
25 #include <osl/diagnose.h>
26 #include <cppuhelper/queryinterface.hxx>
27 #include <ucbhelper/macros.hxx>
28 
29 using namespace com::sun::star::beans;
30 using namespace com::sun::star::lang;
31 using namespace com::sun::star::sdbc;
32 using namespace com::sun::star::ucb;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::util;
35 using namespace cppu;
36 
37 
CachedContentResultSetStub(Reference<XResultSet> const & xOrigin)38 CachedContentResultSetStub::CachedContentResultSetStub( Reference< XResultSet > const & xOrigin )
39                 : ContentResultSetWrapper( xOrigin )
40                 , m_nColumnCount( 0 )
41                 , m_bColumnCountCached( false )
42                 , m_bNeedToPropagateFetchSize( true )
43                 , m_bFirstFetchSizePropagationDone( false )
44                 , m_nLastFetchSize( 1 )//this value is not important at all
45                 , m_bLastFetchDirection( true )//this value is not important at all
46                 , m_aPropertyNameForFetchSize( OUString("FetchSize") )
47                 , m_aPropertyNameForFetchDirection( OUString("FetchDirection") )
48 {
49     impl_init();
50 }
51 
~CachedContentResultSetStub()52 CachedContentResultSetStub::~CachedContentResultSetStub()
53 {
54     impl_deinit();
55 }
56 
57 
58 // XInterface methods.
acquire()59 void SAL_CALL CachedContentResultSetStub::acquire()
60     throw()
61 {
62     OWeakObject::acquire();
63 }
64 
release()65 void SAL_CALL CachedContentResultSetStub::release()
66     throw()
67 {
68     OWeakObject::release();
69 }
70 
71 Any SAL_CALL CachedContentResultSetStub
queryInterface(const Type & rType)72     ::queryInterface( const Type&  rType )
73 {
74     //list all interfaces inclusive baseclasses of interfaces
75 
76     Any aRet = ContentResultSetWrapper::queryInterface( rType );
77     if( aRet.hasValue() )
78         return aRet;
79 
80     aRet = cppu::queryInterface( rType
81                 , static_cast< XTypeProvider* >( this )
82                 , static_cast< XServiceInfo* >( this )
83                 , static_cast< XFetchProvider* >( this )
84                 , static_cast< XFetchProviderForContentAccess* >( this )
85                 );
86 
87     return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
88 }
89 
90 
91 // own methods.  ( inherited )
92 
93 
94 //virtual
95 void CachedContentResultSetStub
impl_propertyChange(const PropertyChangeEvent & rEvt)96     ::impl_propertyChange( const PropertyChangeEvent& rEvt )
97 {
98     impl_EnsureNotDisposed();
99 
100     //don't notify events on fetchsize and fetchdirection to the above CachedContentResultSet
101     //because it will ignore them anyway and we can save this remote calls
102     if(    rEvt.PropertyName == m_aPropertyNameForFetchSize
103         || rEvt.PropertyName == m_aPropertyNameForFetchDirection )
104         return;
105 
106     PropertyChangeEvent aEvt( rEvt );
107     aEvt.Source = static_cast< XPropertySet * >( this );
108     aEvt.Further = false;
109 
110     impl_notifyPropertyChangeListeners( aEvt );
111 }
112 
113 
114 //virtual
115 void CachedContentResultSetStub
impl_vetoableChange(const PropertyChangeEvent & rEvt)116     ::impl_vetoableChange( const PropertyChangeEvent& rEvt )
117 {
118     impl_EnsureNotDisposed();
119 
120     //don't notify events on fetchsize and fetchdirection to the above CachedContentResultSet
121     //because it will ignore them anyway and we can save this remote calls
122     if(    rEvt.PropertyName == m_aPropertyNameForFetchSize
123         || rEvt.PropertyName == m_aPropertyNameForFetchDirection )
124         return;
125 
126     PropertyChangeEvent aEvt( rEvt );
127     aEvt.Source = static_cast< XPropertySet * >( this );
128     aEvt.Further = false;
129 
130     impl_notifyVetoableChangeListeners( aEvt );
131 }
132 
133 
134 // XTypeProvider methods.
135 
136 
XTYPEPROVIDER_COMMON_IMPL(CachedContentResultSetStub)137 XTYPEPROVIDER_COMMON_IMPL( CachedContentResultSetStub )
138 //list all interfaces exclusive baseclasses
139 Sequence< Type > SAL_CALL CachedContentResultSetStub
140     ::getTypes()
141 {
142     static Sequence<Type> ourTypes(
143                 {   CPPU_TYPE_REF( XTypeProvider ),
144                     CPPU_TYPE_REF( XServiceInfo ),
145                     CPPU_TYPE_REF( XComponent ),
146                     CPPU_TYPE_REF( XCloseable ),
147                     CPPU_TYPE_REF( XResultSetMetaDataSupplier ),
148                     CPPU_TYPE_REF( XPropertySet ),
149                     CPPU_TYPE_REF( XPropertyChangeListener ),
150                     CPPU_TYPE_REF( XVetoableChangeListener ),
151                     CPPU_TYPE_REF( XResultSet ),
152                     CPPU_TYPE_REF( XContentAccess ),
153                     CPPU_TYPE_REF( XRow ),
154                     CPPU_TYPE_REF( XFetchProvider ),
155                     CPPU_TYPE_REF( XFetchProviderForContentAccess ) } );
156 
157     return ourTypes;
158 }
159 
160 
161 // XServiceInfo methods.
162 
getImplementationName()163 OUString SAL_CALL CachedContentResultSetStub::getImplementationName()
164 {
165     return "com.sun.star.comp.ucb.CachedContentResultSetStub";
166 }
167 
supportsService(const OUString & ServiceName)168 sal_Bool SAL_CALL CachedContentResultSetStub::supportsService( const OUString& ServiceName )
169 {
170     return cppu::supportsService( this, ServiceName );
171 }
172 
getSupportedServiceNames()173 css::uno::Sequence< OUString > SAL_CALL CachedContentResultSetStub::getSupportedServiceNames()
174 {
175     return { CACHED_CRS_STUB_SERVICE_NAME };
176 }
177 
178 
179 
180 // XFetchProvider methods.
181 
182 
impl_fetchHelper(sal_Int32 nRowStartPosition,sal_Int32 nRowCount,bool bDirection,std::function<void (css::uno::Any & rRowContent)> impl_loadRow)183 FetchResult CachedContentResultSetStub::impl_fetchHelper(
184         sal_Int32 nRowStartPosition, sal_Int32 nRowCount, bool bDirection,
185         std::function<void( css::uno::Any& rRowContent)> impl_loadRow)
186 {
187     impl_EnsureNotDisposed();
188     if( !m_xResultSetOrigin.is() )
189     {
190         OSL_FAIL( "broadcaster was disposed already" );
191         throw RuntimeException();
192     }
193     impl_propagateFetchSizeAndDirection( nRowCount, bDirection );
194     FetchResult aRet;
195     aRet.StartIndex = nRowStartPosition;
196     aRet.Orientation = bDirection;
197     aRet.FetchError = FetchError::SUCCESS; /*ENDOFDATA, EXCEPTION*/
198     sal_Int32 nOldOriginal_Pos = m_xResultSetOrigin->getRow();
199     if( impl_isForwardOnly() )
200     {
201         if( nOldOriginal_Pos != nRowStartPosition )
202         {
203             /*@todo*/
204             aRet.FetchError = FetchError::EXCEPTION;
205             return aRet;
206         }
207         if( nRowCount != 1 )
208             aRet.FetchError = FetchError::EXCEPTION;
209 
210         aRet.Rows.realloc( 1 );
211 
212         try
213         {
214             impl_loadRow( aRet.Rows[0] );
215         }
216         catch( SQLException& )
217         {
218             aRet.Rows.realloc( 0 );
219             aRet.FetchError = FetchError::EXCEPTION;
220             return aRet;
221         }
222         return aRet;
223     }
224     aRet.Rows.realloc( nRowCount );
225     bool bOldOriginal_AfterLast = false;
226     if( !nOldOriginal_Pos )
227         bOldOriginal_AfterLast = m_xResultSetOrigin->isAfterLast();
228     sal_Int32 nN = 1;
229     bool bValidNewPos = false;
230     try
231     {
232         try
233         {
234             /*if( nOldOriginal_Pos != nRowStartPosition )*/
235             bValidNewPos = m_xResultSetOrigin->absolute( nRowStartPosition );
236         }
237         catch( SQLException& )
238         {
239             aRet.Rows.realloc( 0 );
240             aRet.FetchError = FetchError::EXCEPTION;
241             return aRet;
242         }
243         if( !bValidNewPos )
244         {
245             aRet.Rows.realloc( 0 );
246             aRet.FetchError = FetchError::EXCEPTION;
247 
248             /*restore old position*/
249             if( nOldOriginal_Pos )
250                 m_xResultSetOrigin->absolute( nOldOriginal_Pos );
251             else if( bOldOriginal_AfterLast )
252                 m_xResultSetOrigin->afterLast();
253             else
254                 m_xResultSetOrigin->beforeFirst();
255 
256             return aRet;
257         }
258         for( ; nN <= nRowCount; )
259         {
260             impl_loadRow( aRet.Rows[nN-1] );
261             nN++;
262             if( nN <= nRowCount )
263             {
264                 if( bDirection )
265                 {
266                     if( !m_xResultSetOrigin->next() )
267                     {
268                         aRet.Rows.realloc( nN-1 );
269                         aRet.FetchError = FetchError::ENDOFDATA;
270                         break;
271                     }
272                 }
273                 else
274                 {
275                     if( !m_xResultSetOrigin->previous() )
276                     {
277                         aRet.Rows.realloc( nN-1 );
278                         aRet.FetchError = FetchError::ENDOFDATA;
279                         break;
280                     }
281                 }
282             }
283         }
284     }
285     catch( SQLException& )
286     {
287         aRet.Rows.realloc( nN-1 );
288         aRet.FetchError = FetchError::EXCEPTION;
289     }
290     /*restore old position*/
291     if( nOldOriginal_Pos )
292         m_xResultSetOrigin->absolute( nOldOriginal_Pos );
293     else if( bOldOriginal_AfterLast )
294         m_xResultSetOrigin->afterLast();
295     else
296         m_xResultSetOrigin->beforeFirst();
297     return aRet;
298 }
299 
300 FetchResult SAL_CALL CachedContentResultSetStub
fetch(sal_Int32 nRowStartPosition,sal_Int32 nRowCount,sal_Bool bDirection)301     ::fetch( sal_Int32 nRowStartPosition
302     , sal_Int32 nRowCount, sal_Bool bDirection )
303 {
304     impl_init_xRowOrigin();
305     return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection,
306         [&](css::uno::Any& rRowContent)
307         { return impl_getCurrentRowContent(rRowContent, m_xRowOrigin); });
308 }
309 
310 sal_Int32 CachedContentResultSetStub
impl_getColumnCount()311     ::impl_getColumnCount()
312 {
313     sal_Int32 nCount;
314     bool bCached;
315     {
316         osl::Guard< osl::Mutex > aGuard( m_aMutex );
317         nCount = m_nColumnCount;
318         bCached = m_bColumnCountCached;
319     }
320     if( !bCached )
321     {
322         try
323         {
324             Reference< XResultSetMetaData > xMetaData = getMetaData();
325             if( xMetaData.is() )
326                 nCount = xMetaData->getColumnCount();
327         }
328         catch( SQLException& )
329         {
330             OSL_FAIL( "couldn't determine the column count" );
331             nCount = 0;
332         }
333     }
334     osl::Guard< osl::Mutex > aGuard( m_aMutex );
335     m_nColumnCount = nCount;
336     m_bColumnCountCached = true;
337     return m_nColumnCount;
338 }
339 
340 void CachedContentResultSetStub
impl_getCurrentRowContent(Any & rRowContent,const Reference<XRow> & xRow)341     ::impl_getCurrentRowContent( Any& rRowContent
342         , const Reference< XRow >& xRow )
343 {
344     sal_Int32 nCount = impl_getColumnCount();
345 
346     Sequence< Any > aContent( nCount );
347     for( sal_Int32 nN = 1; nN <= nCount; nN++ )
348     {
349         aContent[nN-1] = xRow->getObject( nN, nullptr );
350     }
351 
352     rRowContent <<= aContent;
353 }
354 
355 void CachedContentResultSetStub
impl_propagateFetchSizeAndDirection(sal_Int32 nFetchSize,bool bFetchDirection)356     ::impl_propagateFetchSizeAndDirection( sal_Int32 nFetchSize, bool bFetchDirection )
357 {
358     //this is done only for the case, that there is another CachedContentResultSet in the chain of underlying ResultSets
359 
360     //we do not propagate the property 'FetchSize' or 'FetchDirection' via 'setPropertyValue' from the above CachedContentResultSet to save remote calls
361 
362     //if the underlying ResultSet has a property FetchSize and FetchDirection,
363     //we will set these properties, if the new given parameters are different from the last ones
364 
365     if( !m_bNeedToPropagateFetchSize )
366         return;
367 
368     bool bNeedAction;
369     sal_Int32 nLastSize;
370     bool bLastDirection;
371     bool bFirstPropagationDone;
372     {
373         osl::Guard< osl::Mutex > aGuard( m_aMutex );
374         bNeedAction             = m_bNeedToPropagateFetchSize;
375         nLastSize               = m_nLastFetchSize;
376         bLastDirection          = m_bLastFetchDirection;
377         bFirstPropagationDone   = m_bFirstFetchSizePropagationDone;
378     }
379     if( bNeedAction )
380     {
381         if( nLastSize == nFetchSize
382             && bLastDirection == bFetchDirection
383             && bFirstPropagationDone )
384             return;
385 
386         if(!bFirstPropagationDone)
387         {
388             //check whether the properties 'FetchSize' and 'FetchDirection' do exist
389 
390             Reference< XPropertySetInfo > xPropertySetInfo = getPropertySetInfo();
391             bool bHasSize = xPropertySetInfo->hasPropertyByName( m_aPropertyNameForFetchSize );
392             bool bHasDirection = xPropertySetInfo->hasPropertyByName( m_aPropertyNameForFetchDirection );
393 
394             if(!bHasSize || !bHasDirection)
395             {
396                 osl::Guard< osl::Mutex > aGuard( m_aMutex );
397                 m_bNeedToPropagateFetchSize = false;
398                 return;
399             }
400         }
401 
402         bool bSetSize       = ( nLastSize       !=nFetchSize        ) || !bFirstPropagationDone;
403         bool bSetDirection  = ( bLastDirection  !=bFetchDirection   ) || !bFirstPropagationDone;
404 
405         {
406             osl::Guard< osl::Mutex > aGuard( m_aMutex );
407             m_bFirstFetchSizePropagationDone = true;
408             m_nLastFetchSize        = nFetchSize;
409             m_bLastFetchDirection   = bFetchDirection;
410         }
411 
412         if( bSetSize )
413         {
414             Any aValue;
415             aValue <<= nFetchSize;
416             try
417             {
418                 setPropertyValue( m_aPropertyNameForFetchSize, aValue );
419             }
420             catch( css::uno::Exception& ) {}
421         }
422         if( bSetDirection )
423         {
424             sal_Int32 nFetchDirection = FetchDirection::FORWARD;
425             if( !bFetchDirection )
426                 nFetchDirection = FetchDirection::REVERSE;
427             Any aValue;
428             aValue <<= nFetchDirection;
429             try
430             {
431                 setPropertyValue( m_aPropertyNameForFetchDirection, aValue );
432             }
433             catch( css::uno::Exception& ) {}
434         }
435 
436     }
437 }
438 
439 
440 // XFetchProviderForContentAccess methods.
441 
442 
443 void CachedContentResultSetStub
impl_getCurrentContentIdentifierString(Any & rAny,const Reference<XContentAccess> & xContentAccess)444     ::impl_getCurrentContentIdentifierString( Any& rAny
445         , const Reference< XContentAccess >& xContentAccess )
446 {
447      rAny <<= xContentAccess->queryContentIdentifierString();
448 }
449 
450 void CachedContentResultSetStub
impl_getCurrentContentIdentifier(Any & rAny,const Reference<XContentAccess> & xContentAccess)451     ::impl_getCurrentContentIdentifier( Any& rAny
452         , const Reference< XContentAccess >& xContentAccess )
453 {
454      rAny <<= xContentAccess->queryContentIdentifier();
455 }
456 
457 void CachedContentResultSetStub
impl_getCurrentContent(Any & rAny,const Reference<XContentAccess> & xContentAccess)458     ::impl_getCurrentContent( Any& rAny
459         , const Reference< XContentAccess >& xContentAccess )
460 {
461      rAny <<= xContentAccess->queryContent();
462 }
463 
464 //virtual
465 FetchResult SAL_CALL CachedContentResultSetStub
fetchContentIdentifierStrings(sal_Int32 nRowStartPosition,sal_Int32 nRowCount,sal_Bool bDirection)466     ::fetchContentIdentifierStrings( sal_Int32 nRowStartPosition
467         , sal_Int32 nRowCount, sal_Bool bDirection )
468 {
469     impl_init_xContentAccessOrigin();
470     return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection,
471         [&](css::uno::Any& rRowContent)
472         { return impl_getCurrentContentIdentifierString(rRowContent, m_xContentAccessOrigin); });
473 }
474 
475 //virtual
476 FetchResult SAL_CALL CachedContentResultSetStub
fetchContentIdentifiers(sal_Int32 nRowStartPosition,sal_Int32 nRowCount,sal_Bool bDirection)477     ::fetchContentIdentifiers( sal_Int32 nRowStartPosition
478         , sal_Int32 nRowCount, sal_Bool bDirection )
479 {
480     impl_init_xContentAccessOrigin();
481     return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection,
482         [&](css::uno::Any& rRowContent)
483         { return impl_getCurrentContentIdentifier(rRowContent, m_xContentAccessOrigin); });
484 }
485 
486 //virtual
487 FetchResult SAL_CALL CachedContentResultSetStub
fetchContents(sal_Int32 nRowStartPosition,sal_Int32 nRowCount,sal_Bool bDirection)488     ::fetchContents( sal_Int32 nRowStartPosition
489         , sal_Int32 nRowCount, sal_Bool bDirection )
490 {
491     impl_init_xContentAccessOrigin();
492     return impl_fetchHelper( nRowStartPosition, nRowCount, bDirection,
493         [&](css::uno::Any& rRowContent)
494         { return impl_getCurrentContent(rRowContent, m_xContentAccessOrigin); });
495 }
496 
497 
498 // class CachedContentResultSetStubFactory
499 
500 
CachedContentResultSetStubFactory()501 CachedContentResultSetStubFactory::CachedContentResultSetStubFactory()
502 {
503 }
504 
~CachedContentResultSetStubFactory()505 CachedContentResultSetStubFactory::~CachedContentResultSetStubFactory()
506 {
507 }
508 
509 
510 // CachedContentResultSetStubFactory XServiceInfo methods.
511 
512 XSERVICEINFO_COMMOM_IMPL( CachedContentResultSetStubFactory,
513                           "com.sun.star.comp.ucb.CachedContentResultSetStubFactory" )
514 /// @throws css::uno::Exception
515 static css::uno::Reference< css::uno::XInterface >
CachedContentResultSetStubFactory_CreateInstance(const css::uno::Reference<css::lang::XMultiServiceFactory> &)516 CachedContentResultSetStubFactory_CreateInstance( const css::uno::Reference< css::lang::XMultiServiceFactory> & )
517 {
518     css::lang::XServiceInfo* pX = new CachedContentResultSetStubFactory;
519     return css::uno::Reference< css::uno::XInterface >::query( pX );
520 }
521 css::uno::Sequence< OUString >
getSupportedServiceNames_Static()522 CachedContentResultSetStubFactory::getSupportedServiceNames_Static()
523 {
524     return { CACHED_CRS_STUB_FACTORY_NAME };
525 }
526 
527 // Service factory implementation.
528 
529 
530 ONE_INSTANCE_SERVICE_FACTORY_IMPL( CachedContentResultSetStubFactory );
531 
532 
533 // CachedContentResultSetStubFactory XCachedContentResultSetStubFactory methods.
534 
535 
536     //virtual
537 Reference< XResultSet > SAL_CALL CachedContentResultSetStubFactory
createCachedContentResultSetStub(const Reference<XResultSet> & xSource)538     ::createCachedContentResultSetStub(
539             const Reference< XResultSet > & xSource )
540 {
541     if( xSource.is() )
542     {
543         Reference< XResultSet > xRet = new CachedContentResultSetStub( xSource );
544         return xRet;
545     }
546     return nullptr;
547 }
548 
549 
550 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
551