diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /connectivity/source/cpool | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.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/cpool')
-rw-r--r-- | connectivity/source/cpool/ZConnectionPool.cxx | 301 | ||||
-rw-r--r-- | connectivity/source/cpool/ZConnectionPool.hxx | 146 | ||||
-rw-r--r-- | connectivity/source/cpool/ZConnectionWrapper.cxx | 241 | ||||
-rw-r--r-- | connectivity/source/cpool/ZConnectionWrapper.hxx | 77 | ||||
-rw-r--r-- | connectivity/source/cpool/ZDriverWrapper.cxx | 114 | ||||
-rw-r--r-- | connectivity/source/cpool/ZDriverWrapper.hxx | 73 | ||||
-rw-r--r-- | connectivity/source/cpool/ZPoolCollection.cxx | 468 | ||||
-rw-r--r-- | connectivity/source/cpool/ZPoolCollection.hxx | 133 | ||||
-rw-r--r-- | connectivity/source/cpool/ZPooledConnection.cxx | 72 | ||||
-rw-r--r-- | connectivity/source/cpool/ZPooledConnection.hxx | 58 | ||||
-rw-r--r-- | connectivity/source/cpool/dbpool2.component | 26 |
11 files changed, 1709 insertions, 0 deletions
diff --git a/connectivity/source/cpool/ZConnectionPool.cxx b/connectivity/source/cpool/ZConnectionPool.cxx new file mode 100644 index 000000000..23e6dda1d --- /dev/null +++ b/connectivity/source/cpool/ZConnectionPool.cxx @@ -0,0 +1,301 @@ +/* -*- 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 "ZConnectionPool.hxx" +#include <com/sun/star/lang/XComponent.hpp> +#include "ZPooledConnection.hxx" +#include "ZPoolCollection.hxx" +#include <connectivity/ConnectionWrapper.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::osl; +using namespace connectivity; + +#include <algorithm> + +void SAL_CALL OPoolTimer::onShot() +{ + m_pPool->invalidatePooledConnections(); +} + +constexpr OUStringLiteral TIMEOUT_NODENAME = u"Timeout"; + +OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver, + const Reference< XInterface >& _xDriverNode, + const Reference< css::reflection::XProxyFactory >& _rxProxyFactory) + :m_xDriver(_xDriver) + ,m_xDriverNode(_xDriverNode) + ,m_xProxyFactory(_rxProxyFactory) + ,m_nTimeOut(10) + ,m_nALiveCount(10) +{ + OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!"); + Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY); + if(xProp.is()) + xProp->addPropertyChangeListener(TIMEOUT_NODENAME,this); + + OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount; + calculateTimeOuts(); + + m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0)); + m_xInvalidator->start(); +} + +OConnectionPool::~OConnectionPool() +{ + clear(false); +} + +namespace { + +struct TRemoveEventListenerFunctor +{ + OConnectionPool* m_pConnectionPool; + bool m_bDispose; + + TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool, bool _bDispose) + : m_pConnectionPool(_pConnectionPool) + ,m_bDispose(_bDispose) + { + OSL_ENSURE(m_pConnectionPool,"No connection pool!"); + } + + void dispose(const Reference<XInterface>& _xComponent) + { + Reference< XComponent > xComponent(_xComponent, UNO_QUERY); + + if ( xComponent.is() ) + { + xComponent->removeEventListener(m_pConnectionPool); + if ( m_bDispose ) + xComponent->dispose(); + } + } + + void operator()(const TPooledConnections::value_type& _aValue) + { + dispose(_aValue); + } + + void operator()(const TActiveConnectionMap::value_type& _aValue) + { + dispose(_aValue.first); + } +}; + +struct TConnectionPoolFunctor +{ + OConnectionPool* m_pConnectionPool; + + explicit TConnectionPoolFunctor(OConnectionPool* _pConnectionPool) + : m_pConnectionPool(_pConnectionPool) + { + OSL_ENSURE(m_pConnectionPool,"No connection pool!"); + } + void operator()(const TConnectionMap::value_type& _aValue) + { + std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,true)); + } +}; + +} + +void OConnectionPool::clear(bool _bDispose) +{ + MutexGuard aGuard(m_aMutex); + + if(m_xInvalidator->isTicking()) + m_xInvalidator->stop(); + + std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this)); + m_aPool.clear(); + + std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose)); + m_aActiveConnections.clear(); + + Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(this); + Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY); + if (xProp.is()) + xProp->removePropertyChangeListener(TIMEOUT_NODENAME, this); + + m_xDriverNode.clear(); + m_xDriver.clear(); +} + +Reference< XConnection > OConnectionPool::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) +{ + MutexGuard aGuard(m_aMutex); + + Reference<XConnection> xConnection; + + // create a unique id and look for it in our map + Sequence< PropertyValue > aInfo(_rInfo); + TConnectionMap::key_type nId; + OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); + TConnectionMap::iterator aIter = m_aPool.find(nId); + + if ( m_aPool.end() != aIter ) + xConnection = getPooledConnection(aIter); + + if ( !xConnection.is() ) + xConnection = createNewConnection(_rURL,_rInfo); + + return xConnection; +} + +void SAL_CALL OConnectionPool::disposing( const css::lang::EventObject& Source ) +{ + Reference<XConnection> xConnection(Source.Source,UNO_QUERY); + if(xConnection.is()) + { + MutexGuard aGuard(m_aMutex); + TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection); + OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Connection wasn't in pool"); + if(aIter != m_aActiveConnections.end()) + { // move the pooled connection back to the pool + aIter->second.aPos->second.nALiveCount = m_nALiveCount; + aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection); + m_aActiveConnections.erase(aIter); + } + } + else + { + m_xDriverNode.clear(); + } +} + +Reference< XConnection> OConnectionPool::createNewConnection(const OUString& _rURL,const Sequence< PropertyValue >& _rInfo) +{ + // create new pooled connection + Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory); + // get the new connection from the pooled connection + Reference<XConnection> xConnection = xPooledConnection->getConnection(); + if(xConnection.is()) + { + // add our own as dispose listener to know when we should put the connection back to the pool + Reference< XComponent > xComponent(xConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + // save some information to find the right pool later on + Sequence< PropertyValue > aInfo(_rInfo); + TConnectionMap::key_type nId; + OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); + TConnectionPool aPack; + + // insert the new connection and struct into the active connection map + aPack.nALiveCount = m_nALiveCount; + TActiveConnectionInfo aActiveInfo; + aActiveInfo.aPos = m_aPool.emplace(nId,aPack).first; + aActiveInfo.xPooledConnection = xPooledConnection; + m_aActiveConnections.emplace(xConnection,aActiveInfo); + + if(m_xInvalidator->isExpired()) + m_xInvalidator->start(); + } + + return xConnection; +} + +void OConnectionPool::invalidatePooledConnections() +{ + MutexGuard aGuard(m_aMutex); + TConnectionMap::iterator aIter = m_aPool.begin(); + for (; aIter != m_aPool.end(); ) + { + if(!(--(aIter->second.nALiveCount))) // connections are invalid + { + std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,true)); + + aIter->second.aConnections.clear(); + + // look if the iterator aIter is still present in the active connection map + bool isPresent = std::any_of(m_aActiveConnections.begin(), m_aActiveConnections.end(), + [&aIter](const TActiveConnectionMap::value_type& rEntry) { return rEntry.second.aPos == aIter; }); + if(!isPresent) + {// he isn't so we can delete him + aIter = m_aPool.erase(aIter); + } + else + ++aIter; + } + else + ++aIter; + } + if(!m_aPool.empty()) + m_xInvalidator->start(); +} + +Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator const & _rIter) +{ + Reference<XConnection> xConnection; + + if(!_rIter->second.aConnections.empty()) + { + Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back(); + _rIter->second.aConnections.pop_back(); + + OSL_ENSURE(xPooledConnection.is(),"Can not be null here!"); + xConnection = xPooledConnection->getConnection(); + Reference< XComponent > xComponent(xConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + TActiveConnectionInfo aActiveInfo; + aActiveInfo.aPos = _rIter; + aActiveInfo.xPooledConnection = xPooledConnection; + m_aActiveConnections[xConnection] = aActiveInfo; + } + return xConnection; +} + +void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt ) +{ + if(TIMEOUT_NODENAME == evt.PropertyName) + { + OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount; + calculateTimeOuts(); + } +} + +void OConnectionPool::calculateTimeOuts() +{ + sal_Int32 nTimeOutCorrection = 10; + if(m_nALiveCount < 100) + nTimeOutCorrection = 20; + + m_nTimeOut = m_nALiveCount / nTimeOutCorrection; + m_nALiveCount = m_nALiveCount / m_nTimeOut; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionPool.hxx b/connectivity/source/cpool/ZConnectionPool.hxx new file mode 100644 index 000000000..e83d22849 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionPool.hxx @@ -0,0 +1,146 @@ +/* -*- 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 <sal/config.h> + +#include <map> +#include <vector> + +#include <com/sun/star/sdbc/XPooledConnection.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <cppuhelper/implbase.hxx> +#include <osl/mutex.hxx> +#include <salhelper/timer.hxx> +#include <rtl/ref.hxx> +#include <rtl/digest.h> + +namespace connectivity +{ + class OConnectionPool; + + /// OPoolTimer - Invalidates the connection pool + + class OPoolTimer : public ::salhelper::Timer + { + OConnectionPool* m_pPool; + public: + OPoolTimer(OConnectionPool* _pPool,const ::salhelper::TTimeValue& Time) + : ::salhelper::Timer(Time) + ,m_pPool(_pPool) + {} + protected: + virtual void SAL_CALL onShot() override; + }; + + + // OConnectionPool - the one-instance service for PooledConnections + // manages the active connections and the connections in the pool + + // typedef for the internal structure + typedef std::vector< css::uno::Reference< css::sdbc::XPooledConnection> > TPooledConnections; + + // contains the currently pooled connections + struct TConnectionPool + { + TPooledConnections aConnections; + sal_Int32 nALiveCount; // will be decremented every time a time says to, when will reach zero the pool will be deleted + }; + + struct TDigestHolder + { + sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1]; + TDigestHolder() + { + m_pBuffer[0] = 0; + } + + }; + + // typedef TDigestHolder + + struct TDigestLess + { + bool operator() (const TDigestHolder& x, const TDigestHolder& y) const + { + sal_uInt32 i; + for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i) + ; + return i < RTL_DIGEST_LENGTH_SHA1; + } + }; + + typedef std::map< TDigestHolder,TConnectionPool,TDigestLess> TConnectionMap; + + // contains additional information about an activeconnection which is needed to put it back to the pool + struct TActiveConnectionInfo + { + TConnectionMap::iterator aPos; + css::uno::Reference< css::sdbc::XPooledConnection> xPooledConnection; + }; + + typedef std::map< css::uno::Reference< css::sdbc::XConnection>, + TActiveConnectionInfo> TActiveConnectionMap; + + class OConnectionPool : public ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener> + { + TConnectionMap m_aPool; // the pooled connections + TActiveConnectionMap m_aActiveConnections; // the currently active connections + + ::osl::Mutex m_aMutex; + ::rtl::Reference<OPoolTimer> m_xInvalidator; // invalidates the conntection pool when shot + + css::uno::Reference< css::sdbc::XDriver > m_xDriver; // the one and only driver for this connectionpool + css::uno::Reference< css::uno::XInterface > m_xDriverNode; // config node entry + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + sal_Int32 m_nTimeOut; + sal_Int32 m_nALiveCount; + + private: + css::uno::Reference< css::sdbc::XConnection> createNewConnection(const OUString& _rURL, + const css::uno::Sequence< css::beans::PropertyValue >& _rInfo); + css::uno::Reference< css::sdbc::XConnection> getPooledConnection(TConnectionMap::iterator const & _rIter); + // calculate the timeout and the corresponding ALiveCount + void calculateTimeOuts(); + + protected: + // the dtor will be called from the last instance (last release call) + virtual ~OConnectionPool() override; + public: + OConnectionPool(const css::uno::Reference< css::sdbc::XDriver >& _xDriver, + const css::uno::Reference< css::uno::XInterface >& _xDriverNode, + const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory); + + // delete all refs + void clear(bool _bDispose); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XConnection > getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ); + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + void invalidatePooledConnections(); + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionWrapper.cxx b/connectivity/source/cpool/ZConnectionWrapper.cxx new file mode 100644 index 000000000..dd4519859 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionWrapper.cxx @@ -0,0 +1,241 @@ +/* -*- 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 "ZConnectionWrapper.hxx" + +using namespace connectivity; + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +OConnectionWeakWrapper::OConnectionWeakWrapper(Reference< XAggregation >& _xConnection) + : OConnectionWeakWrapper_BASE(m_aMutex) +{ + setDelegation(_xConnection,m_refCount); + OSL_ENSURE(m_xConnection.is(),"OConnectionWeakWrapper: Connection must be valid!"); +} + +OConnectionWeakWrapper::~OConnectionWeakWrapper() +{ + if ( !OConnectionWeakWrapper_BASE::rBHelper.bDisposed ) + { + osl_atomic_increment( &m_refCount ); + dispose(); + } +} +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OConnectionWeakWrapper, "com.sun.star.sdbc.drivers.OConnectionWeakWrapper", "com.sun.star.sdbc.Connection") + + +Reference< XStatement > SAL_CALL OConnectionWeakWrapper::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->createStatement(); +} + +Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->prepareStatement(sql); +} + +Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareCall( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->prepareCall(sql); +} + +OUString SAL_CALL OConnectionWeakWrapper::nativeSQL( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->nativeSQL(sql); +} + +void SAL_CALL OConnectionWeakWrapper::setAutoCommit( sal_Bool autoCommit ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + m_xConnection->setAutoCommit(autoCommit); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getAutoCommit(); +} + +void SAL_CALL OConnectionWeakWrapper::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->commit(); +} + +void SAL_CALL OConnectionWeakWrapper::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->rollback(); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_xConnection->isClosed(); +} + +Reference< XDatabaseMetaData > SAL_CALL OConnectionWeakWrapper::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getMetaData(); +} + +void SAL_CALL OConnectionWeakWrapper::setReadOnly( sal_Bool readOnly ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setReadOnly(readOnly); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->isReadOnly(); +} + +void SAL_CALL OConnectionWeakWrapper::setCatalog( const OUString& catalog ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setCatalog(catalog); +} + +OUString SAL_CALL OConnectionWeakWrapper::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getCatalog(); +} + +void SAL_CALL OConnectionWeakWrapper::setTransactionIsolation( sal_Int32 level ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setTransactionIsolation(level); +} + +sal_Int32 SAL_CALL OConnectionWeakWrapper::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getTransactionIsolation(); +} + +Reference< css::container::XNameAccess > SAL_CALL OConnectionWeakWrapper::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getTypeMap(); +} + +void SAL_CALL OConnectionWeakWrapper::setTypeMap( const Reference< css::container::XNameAccess >& typeMap ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setTypeMap(typeMap); +} + +// XCloseable +void SAL_CALL OConnectionWeakWrapper::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +void OConnectionWeakWrapper::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OConnectionWeakWrapper_BASE::disposing(); + OConnectionWrapper::disposing(); +} + +// css::lang::XUnoTunnel +IMPLEMENT_FORWARD_REFCOUNT( OConnectionWeakWrapper, OConnectionWeakWrapper_BASE ) + +css::uno::Any SAL_CALL OConnectionWeakWrapper::queryInterface( const css::uno::Type& _rType ) +{ + css::uno::Any aReturn = OConnectionWeakWrapper_BASE::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OConnectionWrapper::queryInterface( _rType ); + return aReturn; +} + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(OConnectionWeakWrapper,OConnectionWeakWrapper_BASE,OConnectionWrapper) + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionWrapper.hxx b/connectivity/source/cpool/ZConnectionWrapper.hxx new file mode 100644 index 000000000..e4b945fa9 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionWrapper.hxx @@ -0,0 +1,77 @@ +/* -*- 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 <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/uno3.hxx> +#include <connectivity/ConnectionWrapper.hxx> + +namespace connectivity +{ + + + // OConnectionWeakWrapper - wraps all methods to the real connection from the driver + // but when disposed it doesn't dispose the real connection + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection > OConnectionWeakWrapper_BASE; + + class OConnectionWeakWrapper : public ::cppu::BaseMutex + , public OConnectionWeakWrapper_BASE + , public OConnectionWrapper + { + protected: + // OComponentHelper + virtual void SAL_CALL disposing() override; + virtual ~OConnectionWeakWrapper() override; + public: + explicit OConnectionWeakWrapper(css::uno::Reference< css::uno::XAggregation >& _xConnection); + + // XServiceInfo + DECLARE_SERVICE_INFO(); + DECLARE_XTYPEPROVIDER() + DECLARE_XINTERFACE( ) + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZDriverWrapper.cxx b/connectivity/source/cpool/ZDriverWrapper.cxx new file mode 100644 index 000000000..811f103bc --- /dev/null +++ b/connectivity/source/cpool/ZDriverWrapper.cxx @@ -0,0 +1,114 @@ +/* -*- 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 "ZDriverWrapper.hxx" +#include "ZConnectionPool.hxx" +#include <osl/diagnose.h> + + +namespace connectivity +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + + ODriverWrapper::ODriverWrapper( Reference< XAggregation >& _rxAggregateDriver, OConnectionPool* _pPool ) + :m_pConnectionPool(_pPool) + { + OSL_ENSURE(_rxAggregateDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate!"); + OSL_ENSURE(m_pConnectionPool.is(), "ODriverWrapper::ODriverWrapper: invalid connection pool!"); + + osl_atomic_increment( &m_refCount ); + if (_rxAggregateDriver.is()) + { + // transfer the (one and only) real ref to the aggregate to our member + m_xDriverAggregate = _rxAggregateDriver; + _rxAggregateDriver = nullptr; + + // a second "real" reference + m_xDriver.set(m_xDriverAggregate, UNO_QUERY); + OSL_ENSURE(m_xDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate (no XDriver)!"); + + // set ourself as delegator + m_xDriverAggregate->setDelegator( static_cast< XWeak* >( this ) ); + } + osl_atomic_decrement( &m_refCount ); + } + + + ODriverWrapper::~ODriverWrapper() + { + if (m_xDriverAggregate.is()) + m_xDriverAggregate->setDelegator(nullptr); + } + + + Any SAL_CALL ODriverWrapper::queryInterface( const Type& _rType ) + { + Any aReturn = ODriverWrapper_BASE::queryInterface(_rType); + return aReturn.hasValue() ? aReturn : (m_xDriverAggregate.is() ? m_xDriverAggregate->queryAggregation(_rType) : aReturn); + } + + + Reference< XConnection > SAL_CALL ODriverWrapper::connect( const OUString& url, const Sequence< PropertyValue >& info ) + { + Reference< XConnection > xConnection; + if (m_pConnectionPool.is()) + // route this through the pool + xConnection = m_pConnectionPool->getConnectionWithInfo( url, info ); + else if (m_xDriver.is()) + xConnection = m_xDriver->connect( url, info ); + + return xConnection; + } + + + sal_Bool SAL_CALL ODriverWrapper::acceptsURL( const OUString& url ) + { + return m_xDriver.is() && m_xDriver->acceptsURL(url); + } + + + Sequence< DriverPropertyInfo > SAL_CALL ODriverWrapper::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info ) + { + Sequence< DriverPropertyInfo > aInfo; + if (m_xDriver.is()) + aInfo = m_xDriver->getPropertyInfo(url, info); + return aInfo; + } + + + sal_Int32 SAL_CALL ODriverWrapper::getMajorVersion( ) + { + return m_xDriver.is() ? m_xDriver->getMajorVersion() : 0; + } + + + sal_Int32 SAL_CALL ODriverWrapper::getMinorVersion( ) + { + return m_xDriver.is() ? m_xDriver->getMinorVersion() : 0; + } + + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZDriverWrapper.hxx b/connectivity/source/cpool/ZDriverWrapper.hxx new file mode 100644 index 000000000..b08cfc3ad --- /dev/null +++ b/connectivity/source/cpool/ZDriverWrapper.hxx @@ -0,0 +1,73 @@ +/* -*- 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 <com/sun/star/sdbc/XDriver.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <com/sun/star/uno/XAggregation.hpp> + + +namespace connectivity +{ + + + class OConnectionPool; + + typedef ::cppu::WeakImplHelper< css::sdbc::XDriver > ODriverWrapper_BASE; + + class ODriverWrapper final : public ODriverWrapper_BASE + { + css::uno::Reference< css::uno::XAggregation > + m_xDriverAggregate; + css::uno::Reference< css::sdbc::XDriver > + m_xDriver; + rtl::Reference<OConnectionPool> + m_pConnectionPool; + + public: + /** creates a new wrapper for a driver + @param _rxAggregateDriver + the driver to aggregate. The object will be reset to <NULL/> when returning from the ctor. + */ + ODriverWrapper( + css::uno::Reference< css::uno::XAggregation >& _rxAggregateDriver, + OConnectionPool* _pPool + ); + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + + private: + /// dtor + virtual ~ODriverWrapper() override; + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + }; + + +} // namespace connectivity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPoolCollection.cxx b/connectivity/source/cpool/ZPoolCollection.cxx new file mode 100644 index 000000000..ba17e6fea --- /dev/null +++ b/connectivity/source/cpool/ZPoolCollection.cxx @@ -0,0 +1,468 @@ +/* -*- 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 "ZPoolCollection.hxx" +#include "ZDriverWrapper.hxx" +#include "ZConnectionPool.hxx" +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/reflection/ProxyFactory.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::reflection; +using namespace ::osl; +using namespace connectivity; + + +static OUString getConnectionPoolNodeName() +{ + return "org.openoffice.Office.DataAccess/ConnectionPool"; +} + +static OUString getEnablePoolingNodeName() +{ + return "EnablePooling"; +} + +static OUString getDriverNameNodeName() +{ + return "DriverName"; +} + +static OUString getDriverSettingsNodeName() +{ + return "DriverSettings"; +} + +static OUString getEnableNodeName() +{ + return "Enable"; +} + + +OPoolCollection::OPoolCollection(const Reference< XComponentContext >& _rxContext) + :m_xContext(_rxContext) +{ + // bootstrap all objects supporting the .sdb.Driver service + m_xManager = DriverManager::create( m_xContext ); + + m_xProxyFactory = ProxyFactory::create( m_xContext ); + + Reference<XPropertySet> xProp(getConfigPoolRoot(),UNO_QUERY); + if ( xProp.is() ) + xProp->addPropertyChangeListener(getEnablePoolingNodeName(),this); + // attach as desktop listener to know when we have to release our pools + osl_atomic_increment( &m_refCount ); + { + + m_xDesktop = css::frame::Desktop::create( m_xContext ); + m_xDesktop->addTerminateListener(this); + + } + osl_atomic_decrement( &m_refCount ); +} + +OPoolCollection::~OPoolCollection() +{ + clearConnectionPools(false); +} + +Reference< XConnection > SAL_CALL OPoolCollection::getConnection( const OUString& _rURL ) +{ + return getConnectionWithInfo(_rURL,Sequence< PropertyValue >()); +} + +Reference< XConnection > SAL_CALL OPoolCollection::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) +{ + MutexGuard aGuard(m_aMutex); + Reference< XConnection > xConnection; + Reference< XDriver > xDriver; + Reference< XInterface > xDriverNode; + OUString sImplName; + if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode) && xDriver.is()) + { + OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode); + + if(pConnectionPool) + xConnection = pConnectionPool->getConnectionWithInfo(_rURL,_rInfo); + } + else if(xDriver.is()) + xConnection = xDriver->connect(_rURL,_rInfo); + + return xConnection; +} + +void SAL_CALL OPoolCollection::setLoginTimeout( sal_Int32 seconds ) +{ + MutexGuard aGuard(m_aMutex); + m_xManager->setLoginTimeout(seconds); +} + +sal_Int32 SAL_CALL OPoolCollection::getLoginTimeout( ) +{ + MutexGuard aGuard(m_aMutex); + return m_xManager->getLoginTimeout(); +} + +OUString SAL_CALL OPoolCollection::getImplementationName( ) +{ + return "com.sun.star.sdbc.OConnectionPool"; +} + +sal_Bool SAL_CALL OPoolCollection::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL OPoolCollection::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ConnectionPool" }; +} + +Reference< XDriver > SAL_CALL OPoolCollection::getDriverByURL( const OUString& _rURL ) +{ + // returns the original driver when no connection pooling is enabled else it returns the proxy + MutexGuard aGuard(m_aMutex); + + Reference< XDriver > xDriver; + Reference< XInterface > xDriverNode; + OUString sImplName; + if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode)) + { + Reference< XDriver > xExistentProxy; + // look if we already have a proxy for this driver + for (const auto& [rxDriver, rxDriverRef] : m_aDriverProxies) + { + // hold the proxy alive as long as we're in this loop round + xExistentProxy = rxDriverRef; + + if (xExistentProxy.is() && (rxDriver.get() == xDriver.get())) + // already created a proxy for this + break; + } + if (xExistentProxy.is()) + { + xDriver = xExistentProxy; + } + else + { // create a new proxy for the driver + // this allows us to control the connections created by it + Reference< XAggregation > xDriverProxy = m_xProxyFactory->createProxy(xDriver); + OSL_ENSURE(xDriverProxy.is(), "OConnectionPool::getDriverByURL: invalid proxy returned by the proxy factory!"); + + OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode); + xDriver = new ODriverWrapper(xDriverProxy, pConnectionPool); + } + } + + return xDriver; +} + +bool OPoolCollection::isDriverPoolingEnabled(std::u16string_view _sDriverImplName, + Reference< XInterface >& _rxDriverNode) +{ + bool bEnabled = false; + Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot(); + // then look for which of them settings are stored in the configuration + Reference< XNameAccess > xDirectAccess(openNode(getDriverSettingsNodeName(),xConnectionPoolRoot),UNO_QUERY); + + if(xDirectAccess.is()) + { + Sequence< OUString > aDriverKeys = xDirectAccess->getElementNames(); + const OUString* pDriverKeys = aDriverKeys.getConstArray(); + const OUString* pDriverKeysEnd = pDriverKeys + aDriverKeys.getLength(); + for (;pDriverKeys != pDriverKeysEnd; ++pDriverKeys) + { + // the name of the driver in this round + if(_sDriverImplName == *pDriverKeys) + { + _rxDriverNode = openNode(*pDriverKeys,xDirectAccess); + if(_rxDriverNode.is()) + getNodeValue(getEnableNodeName(),_rxDriverNode) >>= bEnabled; + break; + } + } + } + return bEnabled; +} + +bool OPoolCollection::isPoolingEnabled() +{ + // the config node where all pooling relevant info are stored under + Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot(); + + // the global "enabled" flag + bool bEnabled = false; + if(xConnectionPoolRoot.is()) + getNodeValue(getEnablePoolingNodeName(),xConnectionPoolRoot) >>= bEnabled; + return bEnabled; +} + +Reference<XInterface> const & OPoolCollection::getConfigPoolRoot() +{ + if(!m_xConfigNode.is()) + m_xConfigNode = createWithProvider( + css::configuration::theDefaultProvider::get(m_xContext), + getConnectionPoolNodeName()); + return m_xConfigNode; +} + +bool OPoolCollection::isPoolingEnabledByUrl(const OUString& _sUrl, + Reference< XDriver >& _rxDriver, + OUString& _rsImplName, + Reference< XInterface >& _rxDriverNode) +{ + bool bEnabled = false; + _rxDriver = m_xManager->getDriverByURL(_sUrl); + if (_rxDriver.is() && isPoolingEnabled()) + { + Reference< XServiceInfo > xServiceInfo(_rxDriver,UNO_QUERY); + OSL_ENSURE(xServiceInfo.is(),"Each driver should have a XServiceInfo interface!"); + + if(xServiceInfo.is()) + { + // look for the implementation name of the driver + _rsImplName = xServiceInfo->getImplementationName(); + bEnabled = isDriverPoolingEnabled(_rsImplName,_rxDriverNode); + } + } + return bEnabled; +} + +void OPoolCollection::clearConnectionPools(bool _bDispose) +{ + for(auto& rEntry : m_aPools) + { + rEntry.second->clear(_bDispose); + } + m_aPools.clear(); +} + +OConnectionPool* OPoolCollection::getConnectionPool(const OUString& _sImplName, + const Reference< XDriver >& _xDriver, + const Reference< XInterface >& _xDriverNode) +{ + OConnectionPool *pRet = nullptr; + OConnectionPools::const_iterator aFind = m_aPools.find(_sImplName); + if (aFind != m_aPools.end()) + pRet = aFind->second.get(); + else if (_xDriver.is() && _xDriverNode.is()) + { + Reference<XPropertySet> xProp(_xDriverNode,UNO_QUERY); + if(xProp.is()) + xProp->addPropertyChangeListener(getEnableNodeName(),this); + rtl::Reference<OConnectionPool> pConnectionPool = new OConnectionPool(_xDriver,_xDriverNode,m_xProxyFactory); + m_aPools.emplace(_sImplName,pConnectionPool); + pRet = pConnectionPool.get(); + } + + OSL_ENSURE(pRet, "Could not query DriverManager from ConnectionPool!"); + + return pRet; +} + +Reference< XInterface > OPoolCollection::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider, + const OUString& _rPath) +{ + OSL_ASSERT(_rxConfProvider.is()); + Sequence< Any > args{ Any(NamedValue( "nodepath", Any(_rPath))) }; + Reference< XInterface > xInterface( + _rxConfProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + args)); + OSL_ENSURE( + xInterface.is(), + "::createWithProvider: could not create the node access!"); + return xInterface; +} + +Reference<XInterface> OPoolCollection::openNode(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept +{ + Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY); + Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY); + Reference< XInterface > xNode; + + try + { + if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath)) + { + xNode.set(xDirectAccess->getByName(_rPath), css::uno::UNO_QUERY); + SAL_WARN_IF( + !xNode.is(), "connectivity.cpool", + "OConfigurationNode::openNode: could not open the node!"); + } + else if (xHierarchyAccess.is()) + { + xNode.set( + xHierarchyAccess->getByHierarchicalName(_rPath), + css::uno::UNO_QUERY); + SAL_WARN_IF( + !xNode.is(), "connectivity.cpool", + "OConfigurationNode::openNode: could not open the node!"); + } + + } + catch(const NoSuchElementException&) + { + SAL_WARN("connectivity.cpool", "::openNode: there is no element named " << + _rPath << "!"); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.cpool", "OConfigurationNode::openNode: caught an exception while retrieving the node"); + } + return xNode; +} + +Any OPoolCollection::getNodeValue(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) noexcept +{ + Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY); + Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY); + Any aReturn; + try + { + if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath) ) + { + aReturn = xDirectAccess->getByName(_rPath); + } + else if (xHierarchyAccess.is()) + { + aReturn = xHierarchyAccess->getByHierarchicalName(_rPath); + } + } + catch(const NoSuchElementException&) + { + TOOLS_WARN_EXCEPTION("connectivity.cpool", "" ); + } + return aReturn; +} + +void SAL_CALL OPoolCollection::queryTermination( const EventObject& /*Event*/ ) +{ +} + +void SAL_CALL OPoolCollection::notifyTermination( const EventObject& /*Event*/ ) +{ + clearDesktop(); +} + +void SAL_CALL OPoolCollection::disposing( const EventObject& Source ) +{ + MutexGuard aGuard(m_aMutex); + if ( m_xDesktop == Source.Source ) + { + clearDesktop(); + } + else + { + try + { + Reference<XPropertySet> xProp(Source.Source,UNO_QUERY); + if(Source.Source == m_xConfigNode) + { + if ( xProp.is() ) + xProp->removePropertyChangeListener(getEnablePoolingNodeName(),this); + m_xConfigNode.clear(); + } + else if ( xProp.is() ) + xProp->removePropertyChangeListener(getEnableNodeName(),this); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.cpool", ""); + } + } +} + +void SAL_CALL OPoolCollection::propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + MutexGuard aGuard(m_aMutex); + if(evt.Source == m_xConfigNode) + { + bool bEnabled = true; + evt.NewValue >>= bEnabled; + if(!bEnabled ) + { + m_aDriverProxies.clear(); + m_aDriverProxies = MapDriver2DriverRef(); + clearConnectionPools(false); + } + } + else if(evt.Source.is()) + { + bool bEnabled = true; + evt.NewValue >>= bEnabled; + if(!bEnabled) + { + OUString sThisDriverName; + getNodeValue(getDriverNameNodeName(),evt.Source) >>= sThisDriverName; + // 1st release the driver + // look if we already have a proxy for this driver + MapDriver2DriverRef::iterator aLookup = m_aDriverProxies.begin(); + while( aLookup != m_aDriverProxies.end()) + { + MapDriver2DriverRef::iterator aFind = aLookup; + Reference<XServiceInfo> xInfo(aLookup->first,UNO_QUERY); + ++aLookup; + if(xInfo.is() && xInfo->getImplementationName() == sThisDriverName) + m_aDriverProxies.erase(aFind); + } + + // 2nd clear the connectionpool + OConnectionPools::iterator aFind = m_aPools.find(sThisDriverName); + if(aFind != m_aPools.end()) + { + aFind->second->clear(false); + m_aPools.erase(aFind); + } + } + } +} + +void OPoolCollection::clearDesktop() +{ + clearConnectionPools(true); + if ( m_xDesktop.is() ) + m_xDesktop->removeTerminateListener(this); + m_xDesktop.clear(); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_OPoolCollection_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new OPoolCollection(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPoolCollection.hxx b/connectivity/source/cpool/ZPoolCollection.hxx new file mode 100644 index 000000000..3fdade8a9 --- /dev/null +++ b/connectivity/source/cpool/ZPoolCollection.hxx @@ -0,0 +1,133 @@ +/* -*- 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 <sal/config.h> + +#include <map> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbc/XDriverManager2.hpp> +#include <com/sun/star/sdbc/XConnectionPool.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> + +namespace connectivity +{ + class OConnectionPool; + + // OPoolCollection - the one-instance service for PooledConnections + // manages the active connections and the connections in the pool + + typedef ::cppu::WeakImplHelper< css::sdbc::XConnectionPool, + css::lang::XServiceInfo, + css::frame::XTerminateListener, + css::beans::XPropertyChangeListener + > OPoolCollection_Base; + + /// OPoolCollection: control the whole connection pooling for oo + class OPoolCollection : public OPoolCollection_Base + { + + + typedef std::map<OUString, rtl::Reference<OConnectionPool>> OConnectionPools; + + typedef std::map< + css::uno::Reference< css::sdbc::XDriver >, + css::uno::WeakReference< css::sdbc::XDriver >> + MapDriver2DriverRef; + + MapDriver2DriverRef m_aDriverProxies; + ::osl::Mutex m_aMutex; + OConnectionPools m_aPools; // the driver pools + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::sdbc::XDriverManager2 > m_xManager; + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + css::uno::Reference< css::uno::XInterface > m_xConfigNode; // config node for general connection pooling + css::uno::Reference< css::frame::XDesktop2> m_xDesktop; + + public: + OPoolCollection(const OPoolCollection&) = delete; + int operator= (const OPoolCollection&) = delete; + + explicit OPoolCollection( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + private: + // some configuration helper methods + css::uno::Reference< css::uno::XInterface > const & getConfigPoolRoot(); + static css::uno::Reference< css::uno::XInterface > createWithProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxConfProvider, + const OUString& _rPath); + static css::uno::Reference< css::uno::XInterface > openNode( const OUString& _rPath, + const css::uno::Reference< css::uno::XInterface >& _xTreeNode) noexcept; + bool isPoolingEnabled(); + bool isDriverPoolingEnabled(std::u16string_view _sDriverImplName, + css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + bool isPoolingEnabledByUrl( const OUString& _sUrl, + css::uno::Reference< css::sdbc::XDriver >& _rxDriver, + OUString& _rsImplName, + css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + + OConnectionPool* getConnectionPool( const OUString& _sImplName, + const css::uno::Reference< css::sdbc::XDriver >& _xDriver, + const css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + void clearConnectionPools(bool _bDispose); + void clearDesktop(); + protected: + virtual ~OPoolCollection() override; + public: + + static css::uno::Any getNodeValue( const OUString& _rPath, + const css::uno::Reference< css::uno::XInterface>& _xTreeNode)noexcept; + + // XDriverManager + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override; + virtual sal_Int32 SAL_CALL getLoginTimeout( ) override; + + //XDriverAccess + virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) 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; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPooledConnection.cxx b/connectivity/source/cpool/ZPooledConnection.cxx new file mode 100644 index 000000000..42e8d6c02 --- /dev/null +++ b/connectivity/source/cpool/ZPooledConnection.cxx @@ -0,0 +1,72 @@ +/* -*- 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 "ZPooledConnection.hxx" +#include "ZConnectionWrapper.hxx" +#include <comphelper/types.hxx> + +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::reflection; +using namespace connectivity; +using namespace ::osl; + +OPooledConnection::OPooledConnection(const Reference< XConnection >& _xConnection, + const Reference< css::reflection::XProxyFactory >& _rxProxyFactory) + : OPooledConnection_Base(m_aMutex) + ,m_xRealConnection(_xConnection) + ,m_xProxyFactory(_rxProxyFactory) +{ + +} + +// OComponentHelper +void SAL_CALL OPooledConnection::disposing() +{ + MutexGuard aGuard(m_aMutex); + if (m_xComponent.is()) + m_xComponent->removeEventListener(this); + m_xComponent.clear(); + ::comphelper::disposeComponent(m_xRealConnection); +} + +// XEventListener +void SAL_CALL OPooledConnection::disposing( const EventObject& /*Source*/ ) +{ +m_xComponent.clear(); +} + +//XPooledConnection +Reference< XConnection > OPooledConnection::getConnection() +{ + if(!m_xComponent.is() && m_xRealConnection.is()) + { + Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(m_xRealConnection); + m_xComponent = new OConnectionWeakWrapper(xConProxy); + // register as event listener for the new connection + if (m_xComponent.is()) + m_xComponent->addEventListener(this); + } + return Reference< XConnection >(m_xComponent,UNO_QUERY); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPooledConnection.hxx b/connectivity/source/cpool/ZPooledConnection.hxx new file mode 100644 index 000000000..79450ea08 --- /dev/null +++ b/connectivity/source/cpool/ZPooledConnection.hxx @@ -0,0 +1,58 @@ +/* -*- 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 <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/sdbc/XPooledConnection.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> + + +namespace connectivity +{ + + // OPooledConnection - + // allows to pool a real connection + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPooledConnection + ,css::lang::XEventListener> OPooledConnection_Base; + + class OPooledConnection : public ::cppu::BaseMutex + ,public OPooledConnection_Base + { + css::uno::Reference< css::sdbc::XConnection > m_xRealConnection; // the connection from driver + css::uno::Reference< css::lang::XComponent > m_xComponent; // the connection which wraps the real connection + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + public: + // OComponentHelper + virtual void SAL_CALL disposing() override; + + OPooledConnection(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory); + + //XPooledConnection + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/dbpool2.component b/connectivity/source/cpool/dbpool2.component new file mode 100644 index 000000000..13f3bac38 --- /dev/null +++ b/connectivity/source/cpool/dbpool2.component @@ -0,0 +1,26 @@ +<?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.sdbc.OConnectionPool" + constructor="connectivity_OPoolCollection_get_implementation"> + <service name="com.sun.star.sdbc.ConnectionPool"/> + </implementation> +</component> |