nss: upgrade to release 3.73
[LibreOffice.git] / connectivity / source / sdbcx / VCollection.cxx
blob860ead949074a5133ec684a1bc58f15982708671
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 <algorithm>
22 #include <com/sun/star/container/ElementExistException.hpp>
23 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
24 #include <connectivity/sdbcx/VCollection.hxx>
25 #include <connectivity/sdbcx/VDescriptor.hxx>
26 #include <com/sun/star/sdbc/SQLException.hpp>
27 #include <connectivity/dbexception.hxx>
28 #include <comphelper/enumhelper.hxx>
29 #include <comphelper/types.hxx>
30 #include <comphelper/property.hxx>
31 #include <comphelper/servicehelper.hxx>
32 #include <cppuhelper/exc_hlp.hxx>
33 #include <o3tl/unreachable.hxx>
34 #include <TConnection.hxx>
35 #include <strings.hrc>
36 #include <resource/sharedresources.hxx>
38 using namespace connectivity::sdbcx;
39 using namespace connectivity;
40 using namespace comphelper;
41 using namespace ::cppu;
42 using namespace ::com::sun::star::beans;
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::sdbc;
46 using namespace ::com::sun::star::container;
47 using namespace ::com::sun::star::util;
49 namespace
51 template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
53 typedef std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap;
54 typedef typename ObjectMap::iterator ObjectIter;
55 typedef typename ObjectMap::value_type ObjectEntry;
57 // private:
58 // this combination of map and vector is used to have a fast name and index access
59 std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
60 ObjectMap m_aNameMap; // hold the elements and a name
61 public:
62 OHardRefMap(bool _bCase)
63 : m_aNameMap(_bCase)
67 virtual bool exists(const OUString& _sName ) override
69 return m_aNameMap.find(_sName) != m_aNameMap.end();
72 virtual bool empty() override
74 return m_aNameMap.empty();
77 virtual void swapAll() override
79 std::vector< ObjectIter >(m_aElements).swap(m_aElements);
80 ObjectMap(m_aNameMap).swap(m_aNameMap);
83 virtual void swap() override
85 std::vector< ObjectIter >().swap(m_aElements);
87 OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
88 ObjectMap( m_aNameMap ).swap( m_aNameMap );
89 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
90 // swapping. This way, it's ensured that the compare object held by these maps is preserved
91 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
92 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
93 // it's case-sensitive flag would have an unpredictable value.
96 virtual void clear() override
98 m_aElements.clear();
99 m_aNameMap.clear();
102 virtual void insert(const OUString& _sName,const ObjectType& _xObject) override
104 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
107 virtual void reFill(const ::std::vector< OUString> &_rVector) override
109 OSL_ENSURE(m_aNameMap.empty(),"OCollection::reFill: collection isn't empty");
110 m_aElements.reserve(_rVector.size());
112 for (auto const& elem : _rVector)
113 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(elem,ObjectType())));
116 virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) override
118 bool bRet = false;
119 ObjectIter aIter = m_aNameMap.find(_sOldName);
120 if ( aIter != m_aNameMap.end() )
122 typename std::vector< ObjectIter >::iterator aFind = std::find(m_aElements.begin(),m_aElements.end(),aIter);
123 if(m_aElements.end() != aFind)
125 (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
126 m_aNameMap.erase(aIter);
128 bRet = true;
131 return bRet;
134 virtual sal_Int32 size() override
136 return static_cast<sal_Int32>(m_aNameMap.size());
139 virtual Sequence< OUString > getElementNames() override
141 Sequence< OUString > aNameList(m_aElements.size());
143 OUString* pStringArray = aNameList.getArray();
144 for(const auto& rIter : m_aElements)
146 *pStringArray = rIter->first;
147 ++pStringArray;
150 return aNameList;
153 virtual OUString getName(sal_Int32 _nIndex) override
155 return m_aElements[_nIndex]->first;
158 virtual void disposeAndErase(sal_Int32 _nIndex) override
160 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
161 Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
162 ::comphelper::disposeComponent(xComp);
163 m_aElements[_nIndex]->second = T();
165 OUString sName = m_aElements[_nIndex]->first;
166 m_aElements.erase(m_aElements.begin()+_nIndex);
167 m_aNameMap.erase(sName);
170 virtual void disposeElements() override
172 for (auto & name : m_aNameMap)
174 Reference<XComponent> xComp(name.second.get(),UNO_QUERY);
175 if ( xComp.is() )
177 ::comphelper::disposeComponent(xComp);
178 name.second = T();
181 m_aElements.clear();
182 m_aNameMap.clear();
185 virtual sal_Int32 findColumn( const OUString& columnName ) override
187 ObjectIter aIter = m_aNameMap.find(columnName);
188 OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
189 return m_aElements.size() - (m_aElements.end() - std::find(m_aElements.begin(),m_aElements.end(),aIter));
192 virtual ObjectType getObject(sal_Int32 _nIndex) override
194 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
195 return m_aElements[_nIndex]->second;
198 virtual ObjectType getObject(const OUString& columnName) override
200 return m_aNameMap.find(columnName)->second;
203 virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) override
205 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
206 m_aElements[_nIndex]->second = _xObject;
209 bool isCaseSensitive() const override
211 return m_aNameMap.key_comp().isCaseSensitive();
217 IObjectCollection::~IObjectCollection() {}
219 IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
221 OCollection::OCollection(::cppu::OWeakObject& _rParent
222 , bool _bCase
223 , ::osl::Mutex& _rMutex
224 , const ::std::vector< OUString> &_rVector
225 , bool _bUseIndexOnly
226 , bool _bUseHardRef)
227 :m_aContainerListeners(_rMutex)
228 ,m_aRefreshListeners(_rMutex)
229 ,m_rParent(_rParent)
230 ,m_rMutex(_rMutex)
231 ,m_bUseIndexOnly(_bUseIndexOnly)
233 if ( _bUseHardRef )
235 m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
237 else
239 m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
241 m_pElements->reFill(_rVector);
244 OCollection::~OCollection()
248 Any SAL_CALL OCollection::queryInterface( const Type & rType )
250 if ( m_bUseIndexOnly && rType == cppu::UnoType<XNameAccess>::get() )
252 return Any();
254 return OCollectionBase::queryInterface( rType );
257 Sequence< Type > SAL_CALL OCollection::getTypes()
259 if ( m_bUseIndexOnly )
261 Sequence< Type > aTypes(OCollectionBase::getTypes());
262 Type* pBegin = aTypes.getArray();
263 Type* pEnd = pBegin + aTypes.getLength();
265 std::vector<Type> aOwnTypes;
266 aOwnTypes.reserve(aTypes.getLength());
267 Type aType = cppu::UnoType<XNameAccess>::get();
268 for(;pBegin != pEnd; ++pBegin)
270 if ( *pBegin != aType )
271 aOwnTypes.push_back(*pBegin);
273 return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
275 return OCollectionBase::getTypes( );
278 void OCollection::clear_NoDispose()
280 ::osl::MutexGuard aGuard(m_rMutex);
282 m_pElements->clear();
283 m_pElements->swapAll();
287 void OCollection::disposing()
289 m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
290 m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
292 ::osl::MutexGuard aGuard(m_rMutex);
294 disposeElements();
296 m_pElements->swap();
299 Any SAL_CALL OCollection::getByIndex( sal_Int32 Index )
301 ::osl::MutexGuard aGuard(m_rMutex);
302 if (Index < 0 || Index >= m_pElements->size() )
303 throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this));
305 return makeAny(getObject(Index));
308 Any SAL_CALL OCollection::getByName( const OUString& aName )
310 ::osl::MutexGuard aGuard(m_rMutex);
312 if ( !m_pElements->exists(aName) )
314 ::connectivity::SharedResources aResources;
315 const OUString sError( aResources.getResourceStringWithSubstitution(
316 STR_NO_ELEMENT_NAME,
317 "$name$", aName
318 ) );
319 throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
322 return makeAny(getObject(m_pElements->findColumn(aName)));
325 Sequence< OUString > SAL_CALL OCollection::getElementNames( )
327 ::osl::MutexGuard aGuard(m_rMutex);
328 return m_pElements->getElementNames();
331 void SAL_CALL OCollection::refresh( )
333 ::osl::MutexGuard aGuard(m_rMutex);
335 disposeElements();
337 impl_refresh();
338 EventObject aEvt(static_cast<XTypeProvider*>(this));
339 m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
342 void OCollection::reFill(const ::std::vector< OUString> &_rVector)
344 m_pElements->reFill(_rVector);
347 // XDataDescriptorFactory
348 Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( )
350 ::osl::MutexGuard aGuard(m_rMutex);
352 return createDescriptor();
355 OUString OCollection::getNameForObject(const ObjectType& _xObject)
357 OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
358 OUString sName;
359 _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
360 return sName;
363 // XAppend
364 void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor )
366 ::osl::ClearableMutexGuard aGuard(m_rMutex);
368 OUString sName = getNameForObject( descriptor );
370 if ( m_pElements->exists(sName) )
371 throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
373 ObjectType xNewlyCreated = appendObject( sName, descriptor );
374 if ( !xNewlyCreated.is() )
375 throw RuntimeException();
377 ODescriptor* pDescriptor = comphelper::getUnoTunnelImplementation<ODescriptor>( xNewlyCreated );
378 if ( pDescriptor )
379 pDescriptor->setNew( false );
381 sName = getNameForObject( xNewlyCreated );
382 if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself
383 m_pElements->insert( sName, xNewlyCreated );
385 // notify our container listeners
386 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any());
387 aGuard.clear();
388 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
391 // XDrop
392 void SAL_CALL OCollection::dropByName( const OUString& elementName )
394 ::osl::MutexGuard aGuard(m_rMutex);
396 if ( !m_pElements->exists(elementName) )
397 throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
399 dropImpl(m_pElements->findColumn(elementName));
402 void SAL_CALL OCollection::dropByIndex( sal_Int32 index )
404 ::osl::MutexGuard aGuard(m_rMutex);
405 if(index <0 || index >= getCount())
406 throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this));
408 dropImpl(index);
411 void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop)
413 OUString elementName = m_pElements->getName(_nIndex);
415 if ( _bReallyDrop )
416 dropObject(_nIndex,elementName);
418 m_pElements->disposeAndErase(_nIndex);
420 // notify our container listeners
421 notifyElementRemoved(elementName);
424 void OCollection::notifyElementRemoved(const OUString& _sName)
426 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any());
427 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
428 OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners);
429 while (aListenerLoop.hasMoreElements())
430 static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent);
433 sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName )
435 if ( !m_pElements->exists(columnName) )
437 ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) );
438 O3TL_UNREACHABLE;
441 return m_pElements->findColumn(columnName) + 1; // because columns start at one
444 Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( )
446 ::osl::MutexGuard aGuard(m_rMutex);
447 return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
450 void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener )
452 m_aContainerListeners.addInterface(_rxListener);
456 void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener )
458 m_aContainerListeners.removeInterface(_rxListener);
461 void SAL_CALL OCollection::acquire() throw()
463 m_rParent.acquire();
466 void SAL_CALL OCollection::release() throw()
468 m_rParent.release();
471 Type SAL_CALL OCollection::getElementType( )
473 return cppu::UnoType<XPropertySet>::get();
476 sal_Bool SAL_CALL OCollection::hasElements( )
478 ::osl::MutexGuard aGuard(m_rMutex);
479 return !m_pElements->empty();
482 sal_Int32 SAL_CALL OCollection::getCount( )
484 ::osl::MutexGuard aGuard(m_rMutex);
485 return m_pElements->size();
488 sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName )
490 ::osl::MutexGuard aGuard(m_rMutex);
491 return m_pElements->exists(aName);
494 void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l )
496 m_aRefreshListeners.addInterface(l);
499 void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l )
501 m_aRefreshListeners.removeInterface(l);
504 void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement)
506 OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
507 if ( !m_pElements->exists(_sElementName) )
508 m_pElements->insert(_sElementName,_xElement);
511 void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName)
513 OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
514 OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
515 OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
516 OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
518 if ( m_pElements->rename(_sOldName,_sNewName) )
520 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName));
521 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
522 OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners);
523 while (aListenerLoop.hasMoreElements())
524 static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent);
528 ObjectType OCollection::getObject(sal_Int32 _nIndex)
530 ObjectType xName = m_pElements->getObject(_nIndex);
531 if ( !xName.is() )
535 xName = createObject(m_pElements->getName(_nIndex));
537 catch(const SQLException& e)
539 css::uno::Any anyEx = cppu::getCaughtException();
542 dropImpl(_nIndex,false);
544 catch(const Exception& )
547 throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),anyEx);
549 m_pElements->setObject(_nIndex,xName);
551 return xName;
554 void OCollection::disposeElements()
556 m_pElements->disposeElements();
559 Reference< XPropertySet > OCollection::createDescriptor()
561 OSL_FAIL("createDescriptor() needs to be overridden when used!");
562 throw SQLException();
565 ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
567 ObjectType xNewDescriptor( createDescriptor() );
568 ::comphelper::copyProperties( _descriptor, xNewDescriptor );
569 return xNewDescriptor;
572 ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
574 return cloneDescriptor( descriptor );
577 void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/)
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */