1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ZConnectionPool.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
35 #include "ZConnectionPool.hxx"
36 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
37 #include <com/sun/star/container/ElementExistException.hpp>
38 #include <comphelper/extract.hxx>
39 #include <comphelper/types.hxx>
40 #include <com/sun/star/lang/XComponent.hpp>
41 #include "ZPooledConnection.hxx"
42 #include "ZPoolCollection.hxx"
43 #ifndef _CONNECTIVITY_CONNECTIONWRAPPER_HXX_
44 #include "connectivity/ConnectionWrapper.hxx"
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #ifndef _CONNECTIVITY_CONNECTIONWRAPPER_HXX_
48 #include "connectivity/ConnectionWrapper.hxx"
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::com::sun::star::sdbc
;
55 using namespace ::com::sun::star::beans
;
56 using namespace ::com::sun::star::container
;
57 using namespace ::osl
;
58 using namespace connectivity
;
62 //==========================================================================
64 //==========================================================================
65 void SAL_CALL
OPoolTimer::onShot()
67 m_pPool
->invalidatePooledConnections();
71 //--------------------------------------------------------------------
72 static const ::rtl::OUString
& getTimeoutNodeName()
74 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("Timeout");
79 //==========================================================================
81 //==========================================================================
82 //--------------------------------------------------------------------------
83 OConnectionPool::OConnectionPool(const Reference
< XDriver
>& _xDriver
,
84 const Reference
< XInterface
>& _xDriverNode
,
85 const Reference
< ::com::sun::star::reflection::XProxyFactory
>& _rxProxyFactory
)
87 ,m_xDriverNode(_xDriverNode
)
88 ,m_xProxyFactory(_rxProxyFactory
)
92 OSL_ENSURE(m_xDriverNode
.is(),"NO valid Driver node set!");
93 Reference
< XComponent
> xComponent(m_xDriverNode
, UNO_QUERY
);
95 xComponent
->addEventListener(this);
97 Reference
<XPropertySet
> xProp(m_xDriverNode
,UNO_QUERY
);
99 xProp
->addPropertyChangeListener(getTimeoutNodeName(),this);
101 OPoolCollection::getNodeValue(getTimeoutNodeName(),m_xDriverNode
) >>= m_nALiveCount
;
104 m_xInvalidator
= new OPoolTimer(this,::vos::TTimeValue(m_nTimeOut
,0));
105 m_xInvalidator
->start();
107 // -----------------------------------------------------------------------------
108 OConnectionPool::~OConnectionPool()
112 // -----------------------------------------------------------------------------
113 struct TRemoveEventListenerFunctor
: ::std::unary_function
<TPooledConnections::value_type
,void>
114 ,::std::unary_function
<TActiveConnectionMap::value_type
,void>
116 OConnectionPool
* m_pConnectionPool
;
119 TRemoveEventListenerFunctor(OConnectionPool
* _pConnectionPool
,sal_Bool _bDispose
= sal_False
)
120 : m_pConnectionPool(_pConnectionPool
)
121 ,m_bDispose(_bDispose
)
123 OSL_ENSURE(m_pConnectionPool
,"No connection pool!");
125 // -----------------------------------------------------------------------------
126 void dispose(const Reference
<XInterface
>& _xComponent
)
128 Reference
< XComponent
> xComponent(_xComponent
, UNO_QUERY
);
130 if ( xComponent
.is() )
132 xComponent
->removeEventListener(m_pConnectionPool
);
134 xComponent
->dispose();
137 // -----------------------------------------------------------------------------
138 void operator()(const TPooledConnections::value_type
& _aValue
)
142 // -----------------------------------------------------------------------------
143 void operator()(const TActiveConnectionMap::value_type
& _aValue
)
145 dispose(_aValue
.first
);
148 // -----------------------------------------------------------------------------
149 struct TConnectionPoolFunctor
: ::std::unary_function
<TConnectionMap::value_type
,void>
151 OConnectionPool
* m_pConnectionPool
;
153 TConnectionPoolFunctor(OConnectionPool
* _pConnectionPool
)
154 : m_pConnectionPool(_pConnectionPool
)
156 OSL_ENSURE(m_pConnectionPool
,"No connection pool!");
158 void operator()(const TConnectionMap::value_type
& _aValue
)
160 ::std::for_each(_aValue
.second
.aConnections
.begin(),_aValue
.second
.aConnections
.end(),TRemoveEventListenerFunctor(m_pConnectionPool
,sal_True
));
163 // -----------------------------------------------------------------------------
164 void OConnectionPool::clear(sal_Bool _bDispose
)
166 MutexGuard
aGuard(m_aMutex
);
168 if(m_xInvalidator
->isTicking())
169 m_xInvalidator
->stop();
171 ::std::for_each(m_aPool
.begin(),m_aPool
.end(),TConnectionPoolFunctor(this));
174 ::std::for_each(m_aActiveConnections
.begin(),m_aActiveConnections
.end(),TRemoveEventListenerFunctor(this,_bDispose
));
175 m_aActiveConnections
.clear();
177 Reference
< XComponent
> xComponent(m_xDriverNode
, UNO_QUERY
);
179 xComponent
->removeEventListener(this);
180 Reference
< XPropertySet
> xProp(m_xDriverNode
, UNO_QUERY
);
182 xProp
->removePropertyChangeListener(getTimeoutNodeName(),this);
184 m_xDriverNode
.clear();
187 //--------------------------------------------------------------------------
188 Reference
< XConnection
> SAL_CALL
OConnectionPool::getConnectionWithInfo( const ::rtl::OUString
& _rURL
, const Sequence
< PropertyValue
>& _rInfo
) throw(SQLException
, RuntimeException
)
190 MutexGuard
aGuard(m_aMutex
);
192 Reference
<XConnection
> xConnection
;
194 // create a unique id and look for it in our map
195 Sequence
< PropertyValue
> aInfo(_rInfo
);
196 TConnectionMap::key_type nId
;
197 OConnectionWrapper::createUniqueId(_rURL
,aInfo
,nId
.m_pBuffer
);
198 TConnectionMap::iterator aIter
= m_aPool
.find(nId
);
200 if ( m_aPool
.end() != aIter
)
201 xConnection
= getPooledConnection(aIter
);
203 if ( !xConnection
.is() )
204 xConnection
= createNewConnection(_rURL
,_rInfo
);
208 //--------------------------------------------------------------------------
209 void SAL_CALL
OConnectionPool::disposing( const ::com::sun::star::lang::EventObject
& Source
) throw (RuntimeException
)
211 Reference
<XConnection
> xConnection(Source
.Source
,UNO_QUERY
);
214 MutexGuard
aGuard(m_aMutex
);
215 TActiveConnectionMap::iterator aIter
= m_aActiveConnections
.find(xConnection
);
216 OSL_ENSURE(aIter
!= m_aActiveConnections
.end(),"OConnectionPool::disposing: Conenction wasn't in pool");
217 if(aIter
!= m_aActiveConnections
.end())
218 { // move the pooled connection back to the pool
219 aIter
->second
.aPos
->second
.nALiveCount
= m_nALiveCount
;
220 aIter
->second
.aPos
->second
.aConnections
.push_back(aIter
->second
.xPooledConnection
);
221 m_aActiveConnections
.erase(aIter
);
226 m_xDriverNode
.clear();
229 // -----------------------------------------------------------------------------
230 Reference
< XConnection
> OConnectionPool::createNewConnection(const ::rtl::OUString
& _rURL
,const Sequence
< PropertyValue
>& _rInfo
)
232 // create new pooled conenction
233 Reference
< XPooledConnection
> xPooledConnection
= new ::connectivity::OPooledConnection(m_xDriver
->connect(_rURL
,_rInfo
),m_xProxyFactory
);
234 // get the new connection from the pooled connection
235 Reference
<XConnection
> xConnection
= xPooledConnection
->getConnection();
238 // add our own as dispose listener to know when we should put the connection back to the pool
239 Reference
< XComponent
> xComponent(xConnection
, UNO_QUERY
);
241 xComponent
->addEventListener(this);
243 // save some information to find the right pool later on
244 Sequence
< PropertyValue
> aInfo(_rInfo
);
245 TConnectionMap::key_type nId
;
246 OConnectionWrapper::createUniqueId(_rURL
,aInfo
,nId
.m_pBuffer
);
247 TConnectionPool aPack
;
249 // insert the new connection and struct into the active connection map
250 aPack
.nALiveCount
= m_nALiveCount
;
251 TActiveConnectionInfo aActiveInfo
;
252 aActiveInfo
.aPos
= m_aPool
.insert(TConnectionMap::value_type(nId
,aPack
)).first
;
253 aActiveInfo
.xPooledConnection
= xPooledConnection
;
254 m_aActiveConnections
.insert(TActiveConnectionMap::value_type(xConnection
,aActiveInfo
));
256 if(m_xInvalidator
->isExpired())
257 m_xInvalidator
->start();
262 // -----------------------------------------------------------------------------
263 void OConnectionPool::invalidatePooledConnections()
265 MutexGuard
aGuard(m_aMutex
);
266 TConnectionMap::iterator aIter
= m_aPool
.begin();
267 for (; aIter
!= m_aPool
.end(); )
269 if(!(--(aIter
->second
.nALiveCount
))) // connections are invalid
271 ::std::for_each(aIter
->second
.aConnections
.begin(),aIter
->second
.aConnections
.end(),TRemoveEventListenerFunctor(this,sal_True
));
273 aIter
->second
.aConnections
.clear();
275 // look if the iterator aIter is still present in the active connection map
276 TActiveConnectionMap::iterator aActIter
= m_aActiveConnections
.begin();
277 for (; aActIter
!= m_aActiveConnections
.end(); ++aActIter
)
279 if(aIter
== aActIter
->second
.aPos
)
282 if(aActIter
== m_aActiveConnections
.end())
283 {// he isn't so we can delete him
284 TConnectionMap::iterator aDeleteIter
= aIter
;
286 m_aPool
.erase(aDeleteIter
);
295 m_xInvalidator
->start();
297 // -----------------------------------------------------------------------------
298 Reference
< XConnection
> OConnectionPool::getPooledConnection(TConnectionMap::iterator
& _rIter
)
300 Reference
<XConnection
> xConnection
;
302 if(!_rIter
->second
.aConnections
.empty())
304 Reference
< XPooledConnection
> xPooledConnection
= _rIter
->second
.aConnections
.back();
305 _rIter
->second
.aConnections
.pop_back();
307 OSL_ENSURE(xPooledConnection
.is(),"Can not be null here!");
308 xConnection
= xPooledConnection
->getConnection();
309 Reference
< XComponent
> xComponent(xConnection
, UNO_QUERY
);
311 xComponent
->addEventListener(this);
313 TActiveConnectionInfo aActiveInfo
;
314 aActiveInfo
.aPos
= _rIter
;
315 aActiveInfo
.xPooledConnection
= xPooledConnection
;
316 m_aActiveConnections
[xConnection
] = aActiveInfo
;
320 // -----------------------------------------------------------------------------
321 void SAL_CALL
OConnectionPool::propertyChange( const PropertyChangeEvent
& evt
) throw (::com::sun::star::uno::RuntimeException
)
323 if(getTimeoutNodeName() == evt
.PropertyName
)
325 evt
.NewValue
>>= m_nALiveCount
;
329 // -----------------------------------------------------------------------------
330 void OConnectionPool::calculateTimeOuts()
332 sal_Int32 nTimeOutCorrection
= 10;
333 if(m_nALiveCount
< 100)
334 nTimeOutCorrection
= 20;
336 m_nTimeOut
= m_nALiveCount
/ nTimeOutCorrection
;
337 m_nALiveCount
= m_nALiveCount
/ m_nTimeOut
;
339 // -----------------------------------------------------------------------------