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