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