summaryrefslogtreecommitdiffstats
path: root/connectivity/source/sdbcx/VCollection.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /connectivity/source/sdbcx/VCollection.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity/source/sdbcx/VCollection.cxx')
-rw-r--r--connectivity/source/sdbcx/VCollection.cxx582
1 files changed, 582 insertions, 0 deletions
diff --git a/connectivity/source/sdbcx/VCollection.cxx b/connectivity/source/sdbcx/VCollection.cxx
new file mode 100644
index 000000000..804c8c361
--- /dev/null
+++ b/connectivity/source/sdbcx/VCollection.cxx
@@ -0,0 +1,582 @@
+/* -*- 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 <algorithm>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/sdbcx/VDescriptor.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/unreachable.hxx>
+#include <TConnection.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+using namespace connectivity::sdbcx;
+using namespace connectivity;
+using namespace comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+
+namespace
+{
+ template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
+ {
+ typedef std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap;
+ typedef typename ObjectMap::iterator ObjectIter;
+ typedef typename ObjectMap::value_type ObjectEntry;
+
+ // private:
+ // this combination of map and vector is used to have a fast name and index access
+ std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
+ ObjectMap m_aNameMap; // hold the elements and a name
+ public:
+ OHardRefMap(bool _bCase)
+ : m_aNameMap(_bCase)
+ {
+ }
+
+ virtual bool exists(const OUString& _sName ) override
+ {
+ return m_aNameMap.find(_sName) != m_aNameMap.end();
+ }
+
+ virtual bool empty() override
+ {
+ return m_aNameMap.empty();
+ }
+
+ virtual void swapAll() override
+ {
+ std::vector< ObjectIter >(m_aElements).swap(m_aElements);
+ ObjectMap(m_aNameMap).swap(m_aNameMap);
+ }
+
+ virtual void swap() override
+ {
+ std::vector< ObjectIter >().swap(m_aElements);
+
+ OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
+ ObjectMap( m_aNameMap ).swap( m_aNameMap );
+ // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
+ // swapping. This way, it's ensured that the compare object held by these maps is preserved
+ // during the swap. If we would not do this, the UStringMixLess instance which is used would be
+ // default constructed (instead of being constructed from the same instance in m_aNameMap), and
+ // it's case-sensitive flag would have an unpredictable value.
+ }
+
+ virtual void clear() override
+ {
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual void insert(const OUString& _sName,const ObjectType& _xObject) override
+ {
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
+ }
+
+ virtual void reFill(const ::std::vector< OUString> &_rVector) override
+ {
+ OSL_ENSURE(m_aNameMap.empty(),"OCollection::reFill: collection isn't empty");
+ m_aElements.reserve(_rVector.size());
+
+ for (auto const& elem : _rVector)
+ m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(elem,ObjectType())));
+ }
+
+ virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) override
+ {
+ bool bRet = false;
+ ObjectIter aIter = m_aNameMap.find(_sOldName);
+ if ( aIter != m_aNameMap.end() )
+ {
+ typename std::vector< ObjectIter >::iterator aFind = std::find(m_aElements.begin(),m_aElements.end(),aIter);
+ if(m_aElements.end() != aFind)
+ {
+ (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
+ m_aNameMap.erase(aIter);
+
+ bRet = true;
+ }
+ }
+ return bRet;
+ }
+
+ virtual sal_Int32 size() override
+ {
+ return static_cast<sal_Int32>(m_aNameMap.size());
+ }
+
+ virtual Sequence< OUString > getElementNames() override
+ {
+ Sequence< OUString > aNameList(m_aElements.size());
+
+ OUString* pStringArray = aNameList.getArray();
+ for(const auto& rIter : m_aElements)
+ {
+ *pStringArray = rIter->first;
+ ++pStringArray;
+ }
+
+ return aNameList;
+ }
+
+ virtual OUString getName(sal_Int32 _nIndex) override
+ {
+ return m_aElements[_nIndex]->first;
+ }
+
+ virtual void disposeAndErase(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ m_aElements[_nIndex]->second = T();
+
+ OUString sName = m_aElements[_nIndex]->first;
+ m_aElements.erase(m_aElements.begin()+_nIndex);
+ m_aNameMap.erase(sName);
+ }
+
+ virtual void disposeElements() override
+ {
+ for (auto & name : m_aNameMap)
+ {
+ Reference<XComponent> xComp(name.second.get(),UNO_QUERY);
+ if ( xComp.is() )
+ {
+ ::comphelper::disposeComponent(xComp);
+ name.second = T();
+ }
+ }
+ m_aElements.clear();
+ m_aNameMap.clear();
+ }
+
+ virtual sal_Int32 findColumn( const OUString& columnName ) override
+ {
+ ObjectIter aIter = m_aNameMap.find(columnName);
+ OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
+ return m_aElements.size() - (m_aElements.end() - std::find(m_aElements.begin(),m_aElements.end(),aIter));
+ }
+
+ virtual ObjectType getObject(sal_Int32 _nIndex) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ return m_aElements[_nIndex]->second;
+ }
+
+ virtual ObjectType getObject(const OUString& columnName) override
+ {
+ return m_aNameMap.find(columnName)->second;
+ }
+
+ virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) override
+ {
+ OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
+ m_aElements[_nIndex]->second = _xObject;
+ }
+
+ bool isCaseSensitive() const override
+ {
+ return m_aNameMap.key_comp().isCaseSensitive();
+ }
+
+ };
+}
+
+IObjectCollection::~IObjectCollection() {}
+
+IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
+
+OCollection::OCollection(::cppu::OWeakObject& _rParent
+ , bool _bCase
+ , ::osl::Mutex& _rMutex
+ , const ::std::vector< OUString> &_rVector
+ , bool _bUseIndexOnly
+ , bool _bUseHardRef)
+ :m_aContainerListeners(_rMutex)
+ ,m_aRefreshListeners(_rMutex)
+ ,m_rParent(_rParent)
+ ,m_rMutex(_rMutex)
+ ,m_bUseIndexOnly(_bUseIndexOnly)
+{
+ if ( _bUseHardRef )
+ {
+ m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
+ }
+ else
+ {
+ m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
+ }
+ m_pElements->reFill(_rVector);
+}
+
+OCollection::~OCollection()
+{
+}
+
+Any SAL_CALL OCollection::queryInterface( const Type & rType )
+{
+ if ( m_bUseIndexOnly && rType == cppu::UnoType<XNameAccess>::get() )
+ {
+ return Any();
+ }
+ return OCollectionBase::queryInterface( rType );
+}
+
+Sequence< Type > SAL_CALL OCollection::getTypes()
+{
+ if ( m_bUseIndexOnly )
+ {
+ Sequence< Type > aTypes(OCollectionBase::getTypes());
+ Type* pBegin = aTypes.getArray();
+ Type* pEnd = pBegin + aTypes.getLength();
+
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ Type aType = cppu::UnoType<XNameAccess>::get();
+ for(;pBegin != pEnd; ++pBegin)
+ {
+ if ( *pBegin != aType )
+ aOwnTypes.push_back(*pBegin);
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+ return OCollectionBase::getTypes( );
+}
+
+void OCollection::clear_NoDispose()
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ m_pElements->clear();
+ m_pElements->swapAll();
+}
+
+
+void OCollection::disposing()
+{
+ m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+ m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
+
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ m_pElements->swap();
+}
+
+Any SAL_CALL OCollection::getByIndex( sal_Int32 Index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if (Index < 0 || Index >= m_pElements->size() )
+ throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this));
+
+ return Any(getObject(Index));
+}
+
+Any SAL_CALL OCollection::getByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(aName) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sError( aResources.getResourceStringWithSubstitution(
+ STR_NO_ELEMENT_NAME,
+ "$name$", aName
+ ) );
+ throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
+ }
+
+ return Any(getObject(m_pElements->findColumn(aName)));
+}
+
+Sequence< OUString > SAL_CALL OCollection::getElementNames( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->getElementNames();
+}
+
+void SAL_CALL OCollection::refresh( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ disposeElements();
+
+ impl_refresh();
+ EventObject aEvt(static_cast<XTypeProvider*>(this));
+ m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
+}
+
+void OCollection::reFill(const ::std::vector< OUString> &_rVector)
+{
+ m_pElements->reFill(_rVector);
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ return createDescriptor();
+}
+
+OUString OCollection::getNameForObject(const ObjectType& _xObject)
+{
+ OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
+ OUString sName;
+ _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
+ return sName;
+}
+
+// XAppend
+void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor )
+{
+ ::osl::ClearableMutexGuard aGuard(m_rMutex);
+
+ OUString sName = getNameForObject( descriptor );
+
+ if ( m_pElements->exists(sName) )
+ throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
+
+ ObjectType xNewlyCreated = appendObject( sName, descriptor );
+ if ( !xNewlyCreated.is() )
+ throw RuntimeException();
+
+ ODescriptor* pDescriptor = comphelper::getFromUnoTunnel<ODescriptor>( xNewlyCreated );
+ if ( pDescriptor )
+ pDescriptor->setNew( false );
+
+ sName = getNameForObject( xNewlyCreated );
+ if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself
+ m_pElements->insert( sName, xNewlyCreated );
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(sName), Any(xNewlyCreated), Any());
+ aGuard.clear();
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+}
+
+// XDrop
+void SAL_CALL OCollection::dropByName( const OUString& elementName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+
+ if ( !m_pElements->exists(elementName) )
+ throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
+
+ dropImpl(m_pElements->findColumn(elementName));
+}
+
+void SAL_CALL OCollection::dropByIndex( sal_Int32 index )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ if(index <0 || index >= getCount())
+ throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this));
+
+ dropImpl(index);
+}
+
+void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop)
+{
+ OUString elementName = m_pElements->getName(_nIndex);
+
+ if ( _bReallyDrop )
+ dropObject(_nIndex,elementName);
+
+ m_pElements->disposeAndErase(_nIndex);
+
+ // notify our container listeners
+ notifyElementRemoved(elementName);
+}
+
+void OCollection::notifyElementRemoved(const OUString& _sName)
+{
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sName), Any(), Any());
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementRemoved(aEvent);
+}
+
+sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName )
+{
+ if ( !m_pElements->exists(columnName) )
+ {
+ ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) );
+ O3TL_UNREACHABLE;
+ }
+
+ return m_pElements->findColumn(columnName) + 1; // because columns start at one
+}
+
+Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
+}
+
+void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+
+void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void SAL_CALL OCollection::acquire() noexcept
+{
+ m_rParent.acquire();
+}
+
+void SAL_CALL OCollection::release() noexcept
+{
+ m_rParent.release();
+}
+
+Type SAL_CALL OCollection::getElementType( )
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL OCollection::hasElements( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return !m_pElements->empty();
+}
+
+sal_Int32 SAL_CALL OCollection::getCount( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->size();
+}
+
+sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_pElements->exists(aName);
+}
+
+void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.addInterface(l);
+}
+
+void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l )
+{
+ m_aRefreshListeners.removeInterface(l);
+}
+
+void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement)
+{
+ OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
+ if ( !m_pElements->exists(_sElementName) )
+ m_pElements->insert(_sElementName,_xElement);
+}
+
+void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName)
+{
+ OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
+ OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
+ OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
+ OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
+
+ if ( m_pElements->rename(_sOldName,_sNewName) )
+ {
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_sNewName), Any(m_pElements->getObject(_sNewName)),Any(_sOldName));
+ // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
+ OInterfaceIteratorHelper3 aListenerLoop(m_aContainerListeners);
+ while (aListenerLoop.hasMoreElements())
+ aListenerLoop.next()->elementReplaced(aEvent);
+ }
+}
+
+ObjectType OCollection::getObject(sal_Int32 _nIndex)
+{
+ ObjectType xName = m_pElements->getObject(_nIndex);
+ if ( !xName.is() )
+ {
+ try
+ {
+ xName = createObject(m_pElements->getName(_nIndex));
+ }
+ catch(const SQLException& e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ try
+ {
+ dropImpl(_nIndex,false);
+ }
+ catch(const Exception& )
+ {
+ }
+ throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),anyEx);
+ }
+ m_pElements->setObject(_nIndex,xName);
+ }
+ return xName;
+}
+
+void OCollection::disposeElements()
+{
+ m_pElements->disposeElements();
+}
+
+Reference< XPropertySet > OCollection::createDescriptor()
+{
+ OSL_FAIL("createDescriptor() needs to be overridden when used!");
+ throw SQLException();
+}
+
+ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
+{
+ ObjectType xNewDescriptor( createDescriptor() );
+ ::comphelper::copyProperties( _descriptor, xNewDescriptor );
+ return xNewDescriptor;
+}
+
+ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
+{
+ return cloneDescriptor( descriptor );
+}
+
+void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/)
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */