/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_connectivity.hxx" #include #include "ZConnectionPool.hxx" #include #include #include #include #include #include "ZPooledConnection.hxx" #include "ZPoolCollection.hxx" #include "connectivity/ConnectionWrapper.hxx" #include #include "connectivity/ConnectionWrapper.hxx" 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 //========================================================================== //= OPoolTimer //========================================================================== void SAL_CALL OPoolTimer::onShot() { m_pPool->invalidatePooledConnections(); } namespace { //-------------------------------------------------------------------- static const ::rtl::OUString& getTimeoutNodeName() { static ::rtl::OUString s_sNodeName( RTL_CONSTASCII_USTRINGPARAM( "Timeout" )); return s_sNodeName; } } //========================================================================== //= OConnectionPool //========================================================================== //-------------------------------------------------------------------------- OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver, const Reference< XInterface >& _xDriverNode, const Reference< ::com::sun::star::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 xProp(m_xDriverNode,UNO_QUERY); if(xProp.is()) xProp->addPropertyChangeListener(getTimeoutNodeName(),this); OPoolCollection::getNodeValue(getTimeoutNodeName(),m_xDriverNode) >>= m_nALiveCount; calculateTimeOuts(); m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0)); m_xInvalidator->start(); } // ----------------------------------------------------------------------------- OConnectionPool::~OConnectionPool() { clear(sal_False); } // ----------------------------------------------------------------------------- struct TRemoveEventListenerFunctor : ::std::unary_function ,::std::unary_function { OConnectionPool* m_pConnectionPool; sal_Bool m_bDispose; TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool,sal_Bool _bDispose = sal_False) : m_pConnectionPool(_pConnectionPool) ,m_bDispose(_bDispose) { OSL_ENSURE(m_pConnectionPool,"No connection pool!"); } // ----------------------------------------------------------------------------- void dispose(const Reference& _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 : ::std::unary_function { OConnectionPool* m_pConnectionPool; 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,sal_True)); } }; // ----------------------------------------------------------------------------- void OConnectionPool::clear(sal_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(getTimeoutNodeName(),this); m_xDriverNode.clear(); m_xDriver.clear(); } //-------------------------------------------------------------------------- Reference< XConnection > SAL_CALL OConnectionPool::getConnectionWithInfo( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) throw(SQLException, RuntimeException) { MutexGuard aGuard(m_aMutex); Reference 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 ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException) { Reference 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: Conenction 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 ::rtl::OUString& _rURL,const Sequence< PropertyValue >& _rInfo) { // create new pooled conenction Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory); // get the new connection from the pooled connection Reference 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.insert(TConnectionMap::value_type(nId,aPack)).first; aActiveInfo.xPooledConnection = xPooledConnection; m_aActiveConnections.insert(TActiveConnectionMap::value_type(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,sal_True)); aIter->second.aConnections.clear(); // look if the iterator aIter is still present in the active connection map TActiveConnectionMap::iterator aActIter = m_aActiveConnections.begin(); for (; aActIter != m_aActiveConnections.end(); ++aActIter) { if(aIter == aActIter->second.aPos) break; } if(aActIter == m_aActiveConnections.end()) {// he isn't so we can delete him TConnectionMap::iterator aDeleteIter = aIter; ++aIter; m_aPool.erase(aDeleteIter); } else ++aIter; } else ++aIter; } if(!m_aPool.empty()) m_xInvalidator->start(); } // ----------------------------------------------------------------------------- Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator& _rIter) { Reference 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 ) throw (::com::sun::star::uno::RuntimeException) { if(getTimeoutNodeName() == evt.PropertyName) { evt.NewValue >>= 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: */