1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_connectivity.hxx" 30 31 #include <stdio.h> 32 #include "ZConnectionPool.hxx" 33 #include <com/sun/star/lang/XSingleServiceFactory.hpp> 34 #include <com/sun/star/container/ElementExistException.hpp> 35 #include <comphelper/extract.hxx> 36 #include <comphelper/types.hxx> 37 #include <com/sun/star/lang/XComponent.hpp> 38 #include "ZPooledConnection.hxx" 39 #include "ZPoolCollection.hxx" 40 #ifndef _CONNECTIVITY_CONNECTIONWRAPPER_HXX_ 41 #include "connectivity/ConnectionWrapper.hxx" 42 #endif 43 #include <com/sun/star/beans/XPropertySet.hpp> 44 #ifndef _CONNECTIVITY_CONNECTIONWRAPPER_HXX_ 45 #include "connectivity/ConnectionWrapper.hxx" 46 #endif 47 48 49 using namespace ::com::sun::star::uno; 50 using namespace ::com::sun::star::lang; 51 using namespace ::com::sun::star::sdbc; 52 using namespace ::com::sun::star::beans; 53 using namespace ::com::sun::star::container; 54 using namespace ::osl; 55 using namespace connectivity; 56 57 #include <algorithm> 58 59 //========================================================================== 60 //= OPoolTimer 61 //========================================================================== 62 void SAL_CALL OPoolTimer::onShot() 63 { 64 m_pPool->invalidatePooledConnections(); 65 } 66 namespace 67 { 68 //-------------------------------------------------------------------- 69 static const ::rtl::OUString& getTimeoutNodeName() 70 { 71 static ::rtl::OUString s_sNodeName = ::rtl::OUString::createFromAscii("Timeout"); 72 return s_sNodeName; 73 } 74 75 } 76 //========================================================================== 77 //= OConnectionPool 78 //========================================================================== 79 //-------------------------------------------------------------------------- 80 OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver, 81 const Reference< XInterface >& _xDriverNode, 82 const Reference< ::com::sun::star::reflection::XProxyFactory >& _rxProxyFactory) 83 :m_xDriver(_xDriver) 84 ,m_xDriverNode(_xDriverNode) 85 ,m_xProxyFactory(_rxProxyFactory) 86 ,m_nTimeOut(10) 87 ,m_nALiveCount(10) 88 { 89 OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!"); 90 Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); 91 if (xComponent.is()) 92 xComponent->addEventListener(this); 93 94 Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY); 95 if(xProp.is()) 96 xProp->addPropertyChangeListener(getTimeoutNodeName(),this); 97 98 OPoolCollection::getNodeValue(getTimeoutNodeName(),m_xDriverNode) >>= m_nALiveCount; 99 calculateTimeOuts(); 100 101 m_xInvalidator = new OPoolTimer(this,::vos::TTimeValue(m_nTimeOut,0)); 102 m_xInvalidator->start(); 103 } 104 // ----------------------------------------------------------------------------- 105 OConnectionPool::~OConnectionPool() 106 { 107 clear(sal_False); 108 } 109 // ----------------------------------------------------------------------------- 110 struct TRemoveEventListenerFunctor : ::std::unary_function<TPooledConnections::value_type,void> 111 ,::std::unary_function<TActiveConnectionMap::value_type,void> 112 { 113 OConnectionPool* m_pConnectionPool; 114 sal_Bool m_bDispose; 115 116 TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool,sal_Bool _bDispose = sal_False) 117 : m_pConnectionPool(_pConnectionPool) 118 ,m_bDispose(_bDispose) 119 { 120 OSL_ENSURE(m_pConnectionPool,"No connection pool!"); 121 } 122 // ----------------------------------------------------------------------------- 123 void dispose(const Reference<XInterface>& _xComponent) 124 { 125 Reference< XComponent > xComponent(_xComponent, UNO_QUERY); 126 127 if ( xComponent.is() ) 128 { 129 xComponent->removeEventListener(m_pConnectionPool); 130 if ( m_bDispose ) 131 xComponent->dispose(); 132 } 133 } 134 // ----------------------------------------------------------------------------- 135 void operator()(const TPooledConnections::value_type& _aValue) 136 { 137 dispose(_aValue); 138 } 139 // ----------------------------------------------------------------------------- 140 void operator()(const TActiveConnectionMap::value_type& _aValue) 141 { 142 dispose(_aValue.first); 143 } 144 }; 145 // ----------------------------------------------------------------------------- 146 struct TConnectionPoolFunctor : ::std::unary_function<TConnectionMap::value_type,void> 147 { 148 OConnectionPool* m_pConnectionPool; 149 150 TConnectionPoolFunctor(OConnectionPool* _pConnectionPool) 151 : m_pConnectionPool(_pConnectionPool) 152 { 153 OSL_ENSURE(m_pConnectionPool,"No connection pool!"); 154 } 155 void operator()(const TConnectionMap::value_type& _aValue) 156 { 157 ::std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,sal_True)); 158 } 159 }; 160 // ----------------------------------------------------------------------------- 161 void OConnectionPool::clear(sal_Bool _bDispose) 162 { 163 MutexGuard aGuard(m_aMutex); 164 165 if(m_xInvalidator->isTicking()) 166 m_xInvalidator->stop(); 167 168 ::std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this)); 169 m_aPool.clear(); 170 171 ::std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose)); 172 m_aActiveConnections.clear(); 173 174 Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); 175 if (xComponent.is()) 176 xComponent->removeEventListener(this); 177 Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY); 178 if (xProp.is()) 179 xProp->removePropertyChangeListener(getTimeoutNodeName(),this); 180 181 m_xDriverNode.clear(); 182 m_xDriver.clear(); 183 } 184 //-------------------------------------------------------------------------- 185 Reference< XConnection > SAL_CALL OConnectionPool::getConnectionWithInfo( const ::rtl::OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) throw(SQLException, RuntimeException) 186 { 187 MutexGuard aGuard(m_aMutex); 188 189 Reference<XConnection> xConnection; 190 191 // create a unique id and look for it in our map 192 Sequence< PropertyValue > aInfo(_rInfo); 193 TConnectionMap::key_type nId; 194 OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); 195 TConnectionMap::iterator aIter = m_aPool.find(nId); 196 197 if ( m_aPool.end() != aIter ) 198 xConnection = getPooledConnection(aIter); 199 200 if ( !xConnection.is() ) 201 xConnection = createNewConnection(_rURL,_rInfo); 202 203 return xConnection; 204 } 205 //-------------------------------------------------------------------------- 206 void SAL_CALL OConnectionPool::disposing( const ::com::sun::star::lang::EventObject& Source ) throw (RuntimeException) 207 { 208 Reference<XConnection> xConnection(Source.Source,UNO_QUERY); 209 if(xConnection.is()) 210 { 211 MutexGuard aGuard(m_aMutex); 212 TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection); 213 OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Conenction wasn't in pool"); 214 if(aIter != m_aActiveConnections.end()) 215 { // move the pooled connection back to the pool 216 aIter->second.aPos->second.nALiveCount = m_nALiveCount; 217 aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection); 218 m_aActiveConnections.erase(aIter); 219 } 220 } 221 else 222 { 223 m_xDriverNode.clear(); 224 } 225 } 226 // ----------------------------------------------------------------------------- 227 Reference< XConnection> OConnectionPool::createNewConnection(const ::rtl::OUString& _rURL,const Sequence< PropertyValue >& _rInfo) 228 { 229 // create new pooled conenction 230 Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory); 231 // get the new connection from the pooled connection 232 Reference<XConnection> xConnection = xPooledConnection->getConnection(); 233 if(xConnection.is()) 234 { 235 // add our own as dispose listener to know when we should put the connection back to the pool 236 Reference< XComponent > xComponent(xConnection, UNO_QUERY); 237 if (xComponent.is()) 238 xComponent->addEventListener(this); 239 240 // save some information to find the right pool later on 241 Sequence< PropertyValue > aInfo(_rInfo); 242 TConnectionMap::key_type nId; 243 OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); 244 TConnectionPool aPack; 245 246 // insert the new connection and struct into the active connection map 247 aPack.nALiveCount = m_nALiveCount; 248 TActiveConnectionInfo aActiveInfo; 249 aActiveInfo.aPos = m_aPool.insert(TConnectionMap::value_type(nId,aPack)).first; 250 aActiveInfo.xPooledConnection = xPooledConnection; 251 m_aActiveConnections.insert(TActiveConnectionMap::value_type(xConnection,aActiveInfo)); 252 253 if(m_xInvalidator->isExpired()) 254 m_xInvalidator->start(); 255 } 256 257 return xConnection; 258 } 259 // ----------------------------------------------------------------------------- 260 void OConnectionPool::invalidatePooledConnections() 261 { 262 MutexGuard aGuard(m_aMutex); 263 TConnectionMap::iterator aIter = m_aPool.begin(); 264 for (; aIter != m_aPool.end(); ) 265 { 266 if(!(--(aIter->second.nALiveCount))) // connections are invalid 267 { 268 ::std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,sal_True)); 269 270 aIter->second.aConnections.clear(); 271 272 // look if the iterator aIter is still present in the active connection map 273 TActiveConnectionMap::iterator aActIter = m_aActiveConnections.begin(); 274 for (; aActIter != m_aActiveConnections.end(); ++aActIter) 275 { 276 if(aIter == aActIter->second.aPos) 277 break; 278 } 279 if(aActIter == m_aActiveConnections.end()) 280 {// he isn't so we can delete him 281 TConnectionMap::iterator aDeleteIter = aIter; 282 ++aIter; 283 m_aPool.erase(aDeleteIter); 284 } 285 else 286 ++aIter; 287 } 288 else 289 ++aIter; 290 } 291 if(!m_aPool.empty()) 292 m_xInvalidator->start(); 293 } 294 // ----------------------------------------------------------------------------- 295 Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator& _rIter) 296 { 297 Reference<XConnection> xConnection; 298 299 if(!_rIter->second.aConnections.empty()) 300 { 301 Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back(); 302 _rIter->second.aConnections.pop_back(); 303 304 OSL_ENSURE(xPooledConnection.is(),"Can not be null here!"); 305 xConnection = xPooledConnection->getConnection(); 306 Reference< XComponent > xComponent(xConnection, UNO_QUERY); 307 if (xComponent.is()) 308 xComponent->addEventListener(this); 309 310 TActiveConnectionInfo aActiveInfo; 311 aActiveInfo.aPos = _rIter; 312 aActiveInfo.xPooledConnection = xPooledConnection; 313 m_aActiveConnections[xConnection] = aActiveInfo; 314 } 315 return xConnection; 316 } 317 // ----------------------------------------------------------------------------- 318 void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt ) throw (::com::sun::star::uno::RuntimeException) 319 { 320 if(getTimeoutNodeName() == evt.PropertyName) 321 { 322 evt.NewValue >>= m_nALiveCount; 323 calculateTimeOuts(); 324 } 325 } 326 // ----------------------------------------------------------------------------- 327 void OConnectionPool::calculateTimeOuts() 328 { 329 sal_Int32 nTimeOutCorrection = 10; 330 if(m_nALiveCount < 100) 331 nTimeOutCorrection = 20; 332 333 m_nTimeOut = m_nALiveCount / nTimeOutCorrection; 334 m_nALiveCount = m_nALiveCount / m_nTimeOut; 335 } 336 // ----------------------------------------------------------------------------- 337