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