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 //==========================================================================
onShot()58 void SAL_CALL OPoolTimer::onShot()
59 {
60 m_pPool->invalidatePooledConnections();
61 }
62 namespace
63 {
64 //--------------------------------------------------------------------
getTimeoutNodeName()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 //--------------------------------------------------------------------------
OConnectionPool(const Reference<XDriver> & _xDriver,const Reference<XInterface> & _xDriverNode,const Reference<::com::sun::star::reflection::XProxyFactory> & _rxProxyFactory)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 // -----------------------------------------------------------------------------
~OConnectionPool()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
TRemoveEventListenerFunctorTRemoveEventListenerFunctor112 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 // -----------------------------------------------------------------------------
disposeTRemoveEventListenerFunctor119 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 // -----------------------------------------------------------------------------
operator ()TRemoveEventListenerFunctor131 void operator()(const TPooledConnections::value_type& _aValue)
132 {
133 dispose(_aValue);
134 }
135 // -----------------------------------------------------------------------------
operator ()TRemoveEventListenerFunctor136 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
TConnectionPoolFunctorTConnectionPoolFunctor146 TConnectionPoolFunctor(OConnectionPool* _pConnectionPool)
147 : m_pConnectionPool(_pConnectionPool)
148 {
149 OSL_ENSURE(m_pConnectionPool,"No connection pool!");
150 }
operator ()TConnectionPoolFunctor151 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 // -----------------------------------------------------------------------------
clear(sal_Bool _bDispose)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 //--------------------------------------------------------------------------
getConnectionWithInfo(const::rtl::OUString & _rURL,const Sequence<PropertyValue> & _rInfo)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 //--------------------------------------------------------------------------
disposing(const::com::sun::star::lang::EventObject & Source)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 // -----------------------------------------------------------------------------
createNewConnection(const::rtl::OUString & _rURL,const Sequence<PropertyValue> & _rInfo)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 // -----------------------------------------------------------------------------
invalidatePooledConnections()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 // -----------------------------------------------------------------------------
getPooledConnection(TConnectionMap::iterator & _rIter)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 // -----------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & evt)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 // -----------------------------------------------------------------------------
calculateTimeOuts()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