cid#1607171 Data race condition
[LibreOffice.git] / ucb / source / cacher / dynamicresultsetwrapper.cxx
blobffa698799baa06a9d09165f4fbbde720f0e4251a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "dynamicresultsetwrapper.hxx"
22 #include <cppuhelper/queryinterface.hxx>
23 #include <osl/diagnose.h>
24 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
25 #include <com/sun/star/ucb/ListActionType.hpp>
26 #include <com/sun/star/ucb/ListenerAlreadySetException.hpp>
27 #include <com/sun/star/ucb/ServiceNotFoundException.hpp>
28 #include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp>
29 #include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp>
31 using namespace com::sun::star::lang;
32 using namespace com::sun::star::sdbc;
33 using namespace com::sun::star::ucb;
34 using namespace com::sun::star::uno;
35 using namespace comphelper;
40 DynamicResultSetWrapper::DynamicResultSetWrapper(
41 Reference< XDynamicResultSet > const & xOrigin
42 , const Reference< XComponentContext > & rxContext )
44 : m_bDisposed( false )
45 , m_bInDispose( false )
46 , m_xContext( rxContext )
47 , m_bStatic( false )
48 , m_bGotWelcome( false )
49 , m_xSource( xOrigin )
50 // , m_xSourceResultCurrent( NULL )
51 // , m_bUseOne( NULL )
53 m_xMyListenerImpl = new DynamicResultSetWrapperListener( this );
54 //call impl_init() at the end of constructor of derived class
57 void DynamicResultSetWrapper::impl_init()
59 //call this at the end of constructor of derived class
62 Reference< XDynamicResultSet > xSource;
64 std::unique_lock aGuard( m_aMutex );
65 xSource = m_xSource;
66 m_xSource = nullptr;
68 if( xSource.is() )
69 setSource( xSource );
72 DynamicResultSetWrapper::~DynamicResultSetWrapper()
74 //call impl_deinit() at start of destructor of derived class
77 void DynamicResultSetWrapper::impl_deinit()
79 //call this at start of destructor of derived class
81 m_xMyListenerImpl->impl_OwnerDies();
84 void DynamicResultSetWrapper::impl_EnsureNotDisposed(std::unique_lock<std::mutex>& /*rGuard*/)
86 if( m_bDisposed )
87 throw DisposedException();
90 //virtual
91 void DynamicResultSetWrapper::impl_InitResultSetOne( std::unique_lock<std::mutex>& /*rGuard*/, const Reference< XResultSet >& xResultSet )
93 OSL_ENSURE( !m_xSourceResultOne.is(), "Source ResultSet One is set already" );
94 m_xSourceResultOne = xResultSet;
95 m_xMyResultOne = xResultSet;
98 //virtual
99 void DynamicResultSetWrapper::impl_InitResultSetTwo( std::unique_lock<std::mutex>& /*rGuard*/, const Reference< XResultSet >& xResultSet )
101 OSL_ENSURE( !m_xSourceResultTwo.is(), "Source ResultSet Two is set already" );
102 m_xSourceResultTwo = xResultSet;
103 m_xMyResultTwo = xResultSet;
106 // XInterface methods.
107 css::uno::Any SAL_CALL DynamicResultSetWrapper::queryInterface( const css::uno::Type & rType )
109 //list all interfaces inclusive baseclasses of interfaces
110 css::uno::Any aRet = cppu::queryInterface( rType,
111 static_cast< XComponent* >(this), //base of XDynamicResultSet
112 static_cast< XDynamicResultSet* >(this),
113 static_cast< XSourceInitialization* >(this)
115 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
118 // XComponent methods.
120 // virtual
121 void SAL_CALL DynamicResultSetWrapper::dispose()
123 std::unique_lock aGuard( m_aMutex );
124 impl_EnsureNotDisposed(aGuard);
126 Reference< XComponent > xSourceComponent;
127 if( m_bInDispose || m_bDisposed )
128 return;
129 m_bInDispose = true;
131 xSourceComponent = m_xSource;
133 if( m_aDisposeEventListeners.getLength(aGuard) )
135 EventObject aEvt;
136 aEvt.Source = static_cast< XComponent * >( this );
137 m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt );
140 /* //@todo ?? ( only if java collection needs to long )
141 if( xSourceComponent.is() )
142 xSourceComponent->dispose();
145 m_bDisposed = true;
146 m_bInDispose = false;
150 // virtual
151 void SAL_CALL DynamicResultSetWrapper::addEventListener( const Reference< XEventListener >& Listener )
153 std::unique_lock aGuard( m_aMutex );
154 impl_EnsureNotDisposed(aGuard);
156 m_aDisposeEventListeners.addInterface( aGuard, Listener );
160 // virtual
161 void SAL_CALL DynamicResultSetWrapper::removeEventListener( const Reference< XEventListener >& Listener )
163 std::unique_lock aGuard( m_aMutex );
164 impl_EnsureNotDisposed(aGuard);
166 m_aDisposeEventListeners.removeInterface( aGuard, Listener );
170 // own methods
173 //virtual
174 void DynamicResultSetWrapper::impl_disposing( const EventObject& )
176 std::unique_lock aGuard( m_aMutex );
178 impl_EnsureNotDisposed(aGuard);
180 if( !m_xSource.is() )
181 return;
183 //release all references to the broadcaster:
184 m_xSource.clear();
185 m_xSourceResultOne.clear();//?? or only when not static??
186 m_xSourceResultTwo.clear();//??
187 //@todo m_xMyResultOne.clear(); ???
188 //@todo m_xMyResultTwo.clear(); ???
191 //virtual
192 void DynamicResultSetWrapper::impl_notify( const ListEvent& Changes )
194 std::unique_lock aGuard( m_aMutex );
195 impl_EnsureNotDisposed(aGuard);
196 //@todo
198 <p>The Listener is allowed to blockade this call, until he really want to go
199 to the new version. The only situation, where the listener has to return the
200 update call at once is, while he disposes his broadcaster or while he is
201 removing himself as listener (otherwise you deadlock)!!!
203 // handle the actions in the list
205 ListEvent aNewEvent;
206 aNewEvent.Source = static_cast< XDynamicResultSet * >( this );
207 aNewEvent.Changes = Changes.Changes;
209 for( ListAction& rAction : asNonConstRange(aNewEvent.Changes) )
211 if (m_bGotWelcome)
212 break;
214 switch( rAction.ListActionType )
216 case ListActionType::WELCOME:
218 WelcomeDynamicResultSetStruct aWelcome;
219 if( rAction.ActionInfo >>= aWelcome )
221 impl_InitResultSetOne( aGuard, aWelcome.Old );
222 impl_InitResultSetTwo( aGuard, aWelcome.New );
223 m_bGotWelcome = true;
225 aWelcome.Old = m_xMyResultOne;
226 aWelcome.New = m_xMyResultTwo;
228 rAction.ActionInfo <<= aWelcome;
230 else
232 OSL_FAIL( "ListActionType was WELCOME but ActionInfo didn't contain a WelcomeDynamicResultSetStruct" );
233 //throw RuntimeException();
235 break;
239 OSL_ENSURE( m_bGotWelcome, "first notification was without WELCOME" );
241 aGuard.unlock();
243 if( !m_xListener.is() )
244 m_aListenerSet.wait();
245 m_xListener->notify( aNewEvent );
248 m_bUseOne = !m_bUseOne;
249 if( m_bUseOne )
250 m_xSourceResultCurrent = m_xSourceResultOne;
251 else
252 m_xSourceResultCurrent = m_xSourceResultTwo;
257 // XSourceInitialization
259 //virtual
260 void SAL_CALL DynamicResultSetWrapper::setSource( const Reference< XInterface > & Source )
262 std::unique_lock aGuard( m_aMutex );
263 impl_EnsureNotDisposed(aGuard);
264 if( m_xSource.is() )
265 throw AlreadyInitializedException();
267 Reference< XDynamicResultSet > xSourceDynamic( Source, UNO_QUERY );
268 OSL_ENSURE( xSourceDynamic.is(),
269 "the given source is not of required type XDynamicResultSet" );
271 Reference< XDynamicResultSetListener > xListener;
272 Reference< XDynamicResultSetListener > xMyListenerImpl;
274 bool bStatic = false;
275 m_xSource = xSourceDynamic;
276 xListener = m_xListener;
277 bStatic = m_bStatic;
278 xMyListenerImpl = m_xMyListenerImpl.get();
279 if( xListener.is() )
280 xSourceDynamic->setListener( m_xMyListenerImpl );
281 else if( bStatic )
283 Reference< XComponent > xSourceComponent( Source, UNO_QUERY );
284 xSourceComponent->addEventListener( xMyListenerImpl );
286 m_aSourceSet.set();
290 // XDynamicResultSet
292 //virtual
293 Reference< XResultSet > SAL_CALL DynamicResultSetWrapper::getStaticResultSet()
295 std::unique_lock aGuard( m_aMutex );
296 impl_EnsureNotDisposed(aGuard);
298 if( m_xListener.is() )
299 throw ListenerAlreadySetException();
301 Reference< XDynamicResultSet > xSource = m_xSource;
302 Reference< XEventListener > xMyListenerImpl = m_xMyListenerImpl;
303 m_bStatic = true;
305 aGuard.unlock();
307 if( xSource.is() )
309 xSource->addEventListener( xMyListenerImpl );
311 if( !xSource.is() )
312 m_aSourceSet.wait();
314 aGuard.lock();
316 Reference< XResultSet > xResultSet = xSource->getStaticResultSet();
317 impl_InitResultSetOne( aGuard, xResultSet );
318 return m_xMyResultOne;
321 //virtual
322 void SAL_CALL DynamicResultSetWrapper::setListener( const Reference< XDynamicResultSetListener > & Listener )
324 std::unique_lock aGuard( m_aMutex );
325 impl_EnsureNotDisposed(aGuard);
327 if( m_xListener.is() )
328 throw ListenerAlreadySetException();
329 if( m_bStatic )
330 throw ListenerAlreadySetException();
332 m_xListener = Listener;
333 m_aDisposeEventListeners.addInterface( aGuard, Listener );
335 Reference< XDynamicResultSet > xSource = m_xSource;
336 Reference< XDynamicResultSetListener > xMyListenerImpl = m_xMyListenerImpl;
338 aGuard.unlock();
340 if ( xSource.is() )
341 xSource->setListener( xMyListenerImpl );
343 m_aListenerSet.set();
346 //virtual
347 void SAL_CALL DynamicResultSetWrapper::connectToCache( const Reference< XDynamicResultSet > & xCache )
349 std::unique_lock aGuard( m_aMutex );
350 impl_EnsureNotDisposed(aGuard);
352 if( m_xListener.is() )
353 throw ListenerAlreadySetException();
354 if( m_bStatic )
355 throw ListenerAlreadySetException();
356 aGuard.unlock();
358 Reference< XSourceInitialization > xTarget( xCache, UNO_QUERY );
359 OSL_ENSURE( xTarget.is(), "The given Target doesn't have the required interface 'XSourceInitialization'" );
360 if( xTarget.is() && m_xContext.is() )
362 //@todo m_aSourceSet.wait();?
364 Reference< XCachedDynamicResultSetStubFactory > xStubFactory;
367 xStubFactory = CachedDynamicResultSetStubFactory::create( m_xContext );
369 catch ( Exception const & )
373 if( xStubFactory.is() )
375 xStubFactory->connectToCache(
376 this, xCache, Sequence< NumberedSortingInfo > (), nullptr );
377 return;
380 OSL_FAIL( "could not connect to cache" );
381 throw ServiceNotFoundException();
384 //virtual
385 sal_Int16 SAL_CALL DynamicResultSetWrapper::getCapabilities()
388 std::unique_lock aGuard( m_aMutex );
389 impl_EnsureNotDisposed(aGuard);
391 m_aSourceSet.wait();
392 Reference< XDynamicResultSet > xSource;
394 std::unique_lock aGuard( m_aMutex );
395 xSource = m_xSource;
397 return xSource->getCapabilities();
403 DynamicResultSetWrapperListener::DynamicResultSetWrapperListener(
404 DynamicResultSetWrapper* pOwner )
405 : m_pOwner( pOwner )
410 DynamicResultSetWrapperListener::~DynamicResultSetWrapperListener()
416 // XInterface methods.
418 void SAL_CALL DynamicResultSetWrapperListener::acquire()
419 noexcept
421 OWeakObject::acquire();
424 void SAL_CALL DynamicResultSetWrapperListener::release()
425 noexcept
427 OWeakObject::release();
430 css::uno::Any SAL_CALL DynamicResultSetWrapperListener::queryInterface( const css::uno::Type & rType )
432 css::uno::Any aRet = cppu::queryInterface( rType,
433 static_cast< XDynamicResultSetListener* >(this),
434 static_cast< XEventListener* >(this)
436 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
439 // XDynamicResultSetListener methods:
441 //virtual
442 void SAL_CALL DynamicResultSetWrapperListener::disposing( const EventObject& rEventObject )
444 std::unique_lock aGuard( m_aMutex );
446 if( m_pOwner )
447 m_pOwner->impl_disposing( rEventObject );
450 //virtual
451 void SAL_CALL DynamicResultSetWrapperListener::notify( const ListEvent& Changes )
453 std::unique_lock aGuard( m_aMutex );
455 if( m_pOwner )
456 m_pOwner->impl_notify( Changes );
460 // own methods:
463 void DynamicResultSetWrapperListener::impl_OwnerDies()
465 std::unique_lock aGuard( m_aMutex );
467 m_pOwner = nullptr;
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */