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: ZPoolCollection.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"
33 #include "ZPoolCollection.hxx"
34 #include "ZDriverWrapper.hxx"
35 #include "ZConnectionPool.hxx"
36 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <comphelper/extract.hxx>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include "diagnose_ex.h"
42 using namespace ::com::sun::star::uno
;
43 using namespace ::com::sun::star::lang
;
44 using namespace ::com::sun::star::sdbc
;
45 using namespace ::com::sun::star::beans
;
46 using namespace ::com::sun::star::container
;
47 using namespace ::com::sun::star::reflection
;
48 using namespace ::osl
;
49 using namespace connectivity
;
51 //--------------------------------------------------------------------
52 static const ::rtl::OUString
& getConnectionPoolNodeName()
54 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("org.openoffice.Office.DataAccess/ConnectionPool");
57 //--------------------------------------------------------------------
58 static const ::rtl::OUString
& getEnablePoolingNodeName()
60 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("EnablePooling");
63 //--------------------------------------------------------------------
64 static const ::rtl::OUString
& getDriverNameNodeName()
66 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("DriverName");
69 // -----------------------------------------------------------------------------
70 static const ::rtl::OUString
& getDriverSettingsNodeName()
72 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("DriverSettings");
75 //--------------------------------------------------------------------------
76 static const ::rtl::OUString
& getEnableNodeName()
78 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("Enable");
82 //--------------------------------------------------------------------
83 OPoolCollection::OPoolCollection(const Reference
< XMultiServiceFactory
>& _rxFactory
)
84 :m_xServiceFactory(_rxFactory
)
86 // bootstrap all objects supporting the .sdb.Driver service
87 m_xManager
= Reference
< XDriverManager
>(m_xServiceFactory
->createInstance(::rtl::OUString::createFromAscii("com.sun.star.sdbc.DriverManager") ), UNO_QUERY
);
88 m_xDriverAccess
= Reference
< XDriverAccess
>(m_xManager
, UNO_QUERY
);
89 OSL_ENSURE(m_xDriverAccess
.is(), "have no (or an invalid) driver manager!");
91 m_xProxyFactory
= Reference
< XProxyFactory
>(
92 m_xServiceFactory
->createInstance(
93 ::rtl::OUString::createFromAscii("com.sun.star.reflection.ProxyFactory")),
95 OSL_ENSURE(m_xProxyFactory
.is(), "OConnectionPool::OConnectionPool: could not create a proxy factory!");
97 Reference
<XPropertySet
> xProp(getConfigPoolRoot(),UNO_QUERY
);
99 xProp
->addPropertyChangeListener(getEnablePoolingNodeName(),this);
100 // attach as desktop listener to know when we have to release our pools
101 osl_incrementInterlockedCount( &m_refCount
);
104 m_xDesktop
= Reference
< ::com::sun::star::frame::XDesktop
>( m_xServiceFactory
->createInstance(::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop") ), UNO_QUERY
);
105 if ( m_xDesktop
.is() )
106 m_xDesktop
->addTerminateListener(this);
109 osl_decrementInterlockedCount( &m_refCount
);
111 // -----------------------------------------------------------------------------
112 OPoolCollection::~OPoolCollection()
114 clearConnectionPools(sal_False
);
116 // -----------------------------------------------------------------------------
117 Reference
< XConnection
> SAL_CALL
OPoolCollection::getConnection( const ::rtl::OUString
& _rURL
) throw(SQLException
, RuntimeException
)
119 return getConnectionWithInfo(_rURL
,Sequence
< PropertyValue
>());
121 // -----------------------------------------------------------------------------
122 Reference
< XConnection
> SAL_CALL
OPoolCollection::getConnectionWithInfo( const ::rtl::OUString
& _rURL
, const Sequence
< PropertyValue
>& _rInfo
) throw(SQLException
, RuntimeException
)
124 MutexGuard
aGuard(m_aMutex
);
125 Reference
< XConnection
> xConnection
;
126 Reference
< XDriver
> xDriver
;
127 Reference
< XInterface
> xDriverNode
;
128 ::rtl::OUString sImplName
;
129 if(isPoolingEnabledByUrl(_rURL
,xDriver
,sImplName
,xDriverNode
) && xDriver
.is())
131 OConnectionPool
* pConnectionPool
= getConnectionPool(sImplName
,xDriver
,xDriverNode
);
134 xConnection
= pConnectionPool
->getConnectionWithInfo(_rURL
,_rInfo
);
136 else if(xDriver
.is())
137 xConnection
= xDriver
->connect(_rURL
,_rInfo
);
141 // -----------------------------------------------------------------------------
142 void SAL_CALL
OPoolCollection::setLoginTimeout( sal_Int32 seconds
) throw(RuntimeException
)
144 MutexGuard
aGuard(m_aMutex
);
145 m_xManager
->setLoginTimeout(seconds
);
147 // -----------------------------------------------------------------------------
148 sal_Int32 SAL_CALL
OPoolCollection::getLoginTimeout( ) throw(RuntimeException
)
150 MutexGuard
aGuard(m_aMutex
);
151 return m_xManager
->getLoginTimeout();
153 // -----------------------------------------------------------------------------
154 ::rtl::OUString SAL_CALL
OPoolCollection::getImplementationName( ) throw(RuntimeException
)
156 MutexGuard
aGuard(m_aMutex
);
157 return getImplementationName_Static();
160 //--------------------------------------------------------------------------
161 sal_Bool SAL_CALL
OPoolCollection::supportsService( const ::rtl::OUString
& _rServiceName
) throw(RuntimeException
)
163 Sequence
< ::rtl::OUString
> aSupported(getSupportedServiceNames());
164 const ::rtl::OUString
* pSupported
= aSupported
.getConstArray();
165 const ::rtl::OUString
* pEnd
= pSupported
+ aSupported
.getLength();
166 for (;pSupported
!= pEnd
&& !pSupported
->equals(_rServiceName
); ++pSupported
)
169 return pSupported
!= pEnd
;
172 //--------------------------------------------------------------------------
173 Sequence
< ::rtl::OUString
> SAL_CALL
OPoolCollection::getSupportedServiceNames( ) throw(RuntimeException
)
175 return getSupportedServiceNames_Static();
178 //---------------------------------------OPoolCollection----------------------------------
179 Reference
< XInterface
> SAL_CALL
OPoolCollection::CreateInstance(const Reference
< XMultiServiceFactory
>& _rxFactory
)
181 return static_cast<XDriverManager
*>(new OPoolCollection(_rxFactory
));
184 //--------------------------------------------------------------------------
185 ::rtl::OUString SAL_CALL
OPoolCollection::getImplementationName_Static( ) throw(RuntimeException
)
187 return ::rtl::OUString::createFromAscii("com.sun.star.sdbc.OConnectionPool");
190 //--------------------------------------------------------------------------
191 Sequence
< ::rtl::OUString
> SAL_CALL
OPoolCollection::getSupportedServiceNames_Static( ) throw(RuntimeException
)
193 Sequence
< ::rtl::OUString
> aSupported(1);
194 aSupported
[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdbc.ConnectionPool");
197 // -----------------------------------------------------------------------------
198 Reference
< XDriver
> SAL_CALL
OPoolCollection::getDriverByURL( const ::rtl::OUString
& _rURL
) throw(RuntimeException
)
200 // returns the original driver when no connection pooling is enabled else it returns the proxy
201 MutexGuard
aGuard(m_aMutex
);
203 Reference
< XDriver
> xDriver
;
204 Reference
< XInterface
> xDriverNode
;
205 ::rtl::OUString sImplName
;
206 if(isPoolingEnabledByUrl(_rURL
,xDriver
,sImplName
,xDriverNode
))
208 Reference
< XDriver
> xExistentProxy
;
209 // look if we already have a proxy for this driver
210 for ( ConstMapDriver2DriverRefIterator aLookup
= m_aDriverProxies
.begin();
211 aLookup
!= m_aDriverProxies
.end();
215 // hold the proxy alive as long as we're in this loop round
216 xExistentProxy
= aLookup
->second
;
218 if (xExistentProxy
.is() && (aLookup
->first
.get() == xDriver
.get()))
219 // already created a proxy for this
222 if (xExistentProxy
.is())
224 xDriver
= xExistentProxy
;
227 { // create a new proxy for the driver
228 // this allows us to control the connections created by it
229 if (m_xProxyFactory
.is())
231 Reference
< XAggregation
> xDriverProxy
= m_xProxyFactory
->createProxy(xDriver
.get());
232 OSL_ENSURE(xDriverProxy
.is(), "OConnectionPool::getDriverByURL: invalid proxy returned by the proxy factory!");
234 OConnectionPool
* pConnectionPool
= getConnectionPool(sImplName
,xDriver
,xDriverNode
);
235 xDriver
= new ODriverWrapper(xDriverProxy
, pConnectionPool
);
238 OSL_ENSURE(sal_False
, "OConnectionPool::getDriverByURL: could not instantiate a proxy factory!");
244 // -----------------------------------------------------------------------------
245 sal_Bool
OPoolCollection::isDriverPoolingEnabled(const ::rtl::OUString
& _sDriverImplName
,
246 Reference
< XInterface
>& _rxDriverNode
)
248 sal_Bool bEnabled
= sal_False
;
249 Reference
<XInterface
> xConnectionPoolRoot
= getConfigPoolRoot();
250 // then look for which of them settings are stored in the configuration
251 Reference
< XNameAccess
> xDirectAccess(openNode(getDriverSettingsNodeName(),xConnectionPoolRoot
),UNO_QUERY
);
253 if(xDirectAccess
.is())
255 Sequence
< ::rtl::OUString
> aDriverKeys
= xDirectAccess
->getElementNames();
256 const ::rtl::OUString
* pDriverKeys
= aDriverKeys
.getConstArray();
257 const ::rtl::OUString
* pDriverKeysEnd
= pDriverKeys
+ aDriverKeys
.getLength();
258 for (;pDriverKeys
!= pDriverKeysEnd
; ++pDriverKeys
)
260 // the name of the driver in this round
261 if(_sDriverImplName
== *pDriverKeys
)
263 _rxDriverNode
= openNode(*pDriverKeys
,xDirectAccess
);
264 if(_rxDriverNode
.is())
265 getNodeValue(getEnableNodeName(),_rxDriverNode
) >>= bEnabled
;
272 // -----------------------------------------------------------------------------
273 sal_Bool
OPoolCollection::isPoolingEnabled()
275 // the config node where all pooling relevant info are stored under
276 Reference
<XInterface
> xConnectionPoolRoot
= getConfigPoolRoot();
278 // the global "enabled" flag
279 sal_Bool bEnabled
= sal_False
;
280 if(xConnectionPoolRoot
.is())
281 getNodeValue(getEnablePoolingNodeName(),xConnectionPoolRoot
) >>= bEnabled
;
284 // -----------------------------------------------------------------------------
285 Reference
<XInterface
> OPoolCollection::getConfigPoolRoot()
287 if(!m_xConfigNode
.is())
288 m_xConfigNode
= createWithServiceFactory(getConnectionPoolNodeName());
289 return m_xConfigNode
;
291 // -----------------------------------------------------------------------------
292 sal_Bool
OPoolCollection::isPoolingEnabledByUrl(const ::rtl::OUString
& _sUrl
,
293 Reference
< XDriver
>& _rxDriver
,
294 ::rtl::OUString
& _rsImplName
,
295 Reference
< XInterface
>& _rxDriverNode
)
297 sal_Bool bEnabled
= sal_False
;
298 if (m_xDriverAccess
.is())
300 _rxDriver
= m_xDriverAccess
->getDriverByURL(_sUrl
);
301 if (_rxDriver
.is() && isPoolingEnabled())
303 Reference
< XServiceInfo
> xSerivceInfo(_rxDriver
,UNO_QUERY
);
304 OSL_ENSURE(xSerivceInfo
.is(),"Each driver should have a XServiceInfo interface!");
306 if(xSerivceInfo
.is())
308 // look for the implementation name of the driver
309 _rsImplName
= xSerivceInfo
->getImplementationName();
310 bEnabled
= isDriverPoolingEnabled(_rsImplName
,_rxDriverNode
);
316 // -----------------------------------------------------------------------------
317 void OPoolCollection::clearConnectionPools(sal_Bool _bDispose
)
319 OConnectionPools::const_iterator aIter
= m_aPools
.begin();
320 while(aIter
!= m_aPools
.end())
322 aIter
->second
->clear(_bDispose
);
323 aIter
->second
->release();
324 ::rtl::OUString sKeyValue
= aIter
->first
;
326 m_aPools
.erase(sKeyValue
);
329 // -----------------------------------------------------------------------------
330 OConnectionPool
* OPoolCollection::getConnectionPool(const ::rtl::OUString
& _sImplName
,
331 const Reference
< XDriver
>& _xDriver
,
332 const Reference
< XInterface
>& _xDriverNode
)
334 OConnectionPool
*pRet
= 0;
335 OConnectionPools::const_iterator aFind
= m_aPools
.find(_sImplName
);
336 if (aFind
!= m_aPools
.end())
337 pRet
= aFind
->second
;
338 else if (_xDriver
.is() && _xDriverNode
.is())
340 Reference
<XPropertySet
> xProp(_xDriverNode
,UNO_QUERY
);
342 xProp
->addPropertyChangeListener(getEnableNodeName(),this);
343 OConnectionPool
* pConnectionPool
= new OConnectionPool(_xDriver
,_xDriverNode
,m_xProxyFactory
);
344 pConnectionPool
->acquire();
345 aFind
= m_aPools
.insert(OConnectionPools::value_type(_sImplName
,pConnectionPool
)).first
;
346 pRet
= aFind
->second
;
349 OSL_ENSURE(pRet
, "Could not query DriverManager from ConnectionPool!");
353 // -----------------------------------------------------------------------------
354 Reference
< XInterface
> OPoolCollection::createWithServiceFactory(const ::rtl::OUString
& _rPath
) const
356 Reference
< XInterface
> xInterface
;
359 Reference
< XInterface
> xProvider
= m_xServiceFactory
->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.ConfigurationProvider")));
360 OSL_ENSURE(xProvider
.is(), "OConfigurationTreeRoot::createWithServiceFactory: could not instantiate the config provider service!");
361 Reference
< XMultiServiceFactory
> xProviderAsFac(xProvider
, UNO_QUERY
);
362 OSL_ENSURE(xProviderAsFac
.is() || !xProvider
.is(), "OConfigurationTreeRoot::createWithServiceFactory: the provider is missing an interface!");
363 if (xProviderAsFac
.is())
364 xInterface
= createWithProvider(xProviderAsFac
, _rPath
);
366 catch(const Exception
&)
368 OSL_ENSURE(sal_False
, "createWithServiceFactory: error while instantiating the provider service!");
372 //------------------------------------------------------------------------
373 Reference
< XInterface
> OPoolCollection::createWithProvider(const Reference
< XMultiServiceFactory
>& _rxConfProvider
,
374 const ::rtl::OUString
& _rPath
) const
376 OSL_ENSURE(_rxConfProvider
.is(), "createWithProvider: invalid provider!");
378 Reference
< XInterface
> xInterface
;
380 if (_rxConfProvider
.is())
384 Reference
< XServiceInfo
> xSI(_rxConfProvider
, UNO_QUERY
);
387 OSL_ENSURE(sal_False
, "::createWithProvider: no XServiceInfo interface on the provider!");
391 OSL_ENSURE(xSI
->supportsService(::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationProvider")),
392 "::createWithProvider: sure this is a provider? Missing the ConfigurationProvider service!");
395 catch(const Exception
&)
397 OSL_ENSURE(sal_False
, "::createWithProvider: unable to check the service conformance of the provider given!");
402 if (_rxConfProvider
.is())
406 Sequence
< Any
> aCreationArgs(3);
407 aCreationArgs
[0] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("nodepath")), 0, makeAny(_rPath
), PropertyState_DIRECT_VALUE
));
408 aCreationArgs
[1] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("depth")), 0, makeAny((sal_Int32
)-1), PropertyState_DIRECT_VALUE
));
409 aCreationArgs
[2] = makeAny(PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("lazywrite")), 0, makeAny(sal_True
), PropertyState_DIRECT_VALUE
));
411 static ::rtl::OUString sAccessService
= ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationAccess");
413 xInterface
= _rxConfProvider
->createInstanceWithArguments(sAccessService
, aCreationArgs
);
414 OSL_ENSURE(xInterface
.is(), "::createWithProvider: could not create the node access!");
418 OSL_ENSURE(sal_False
, "OConfigurationTreeRoot::createWithProvider: caught an exception while creating the access object!");
423 // -----------------------------------------------------------------------------
424 Reference
<XInterface
> OPoolCollection::openNode(const ::rtl::OUString
& _rPath
,const Reference
<XInterface
>& _xTreeNode
) const throw()
426 Reference
< XHierarchicalNameAccess
> xHierarchyAccess(_xTreeNode
, UNO_QUERY
);
427 Reference
< XNameAccess
> xDirectAccess(_xTreeNode
, UNO_QUERY
);
428 Reference
< XInterface
> xNode
;
432 if (xDirectAccess
.is() && xDirectAccess
->hasByName(_rPath
))
434 if (!::cppu::extractInterface(xNode
, xDirectAccess
->getByName(_rPath
)))
435 OSL_ENSURE(sal_False
, "OConfigurationNode::openNode: could not open the node!");
437 else if (xHierarchyAccess
.is())
439 if (!::cppu::extractInterface(xNode
, xHierarchyAccess
->getByHierarchicalName(_rPath
)))
440 OSL_ENSURE(sal_False
, "OConfigurationNode::openNode: could not open the node!");
444 catch(const NoSuchElementException
&)
446 OSL_ENSURE(sal_False
,
447 ::rtl::OString("::openNode: there is no element named ")
448 += ::rtl::OString(_rPath
.getStr(), _rPath
.getLength(), RTL_TEXTENCODING_ASCII_US
)
449 += ::rtl::OString("!"));
453 OSL_ENSURE(sal_False
, "OConfigurationNode::openNode: caught an exception while retrieving the node!");
457 // -----------------------------------------------------------------------------
458 Any
OPoolCollection::getNodeValue(const ::rtl::OUString
& _rPath
,const Reference
<XInterface
>& _xTreeNode
) throw()
460 Reference
< XHierarchicalNameAccess
> xHierarchyAccess(_xTreeNode
, UNO_QUERY
);
461 Reference
< XNameAccess
> xDirectAccess(_xTreeNode
, UNO_QUERY
);
465 if (xDirectAccess
.is() && xDirectAccess
->hasByName(_rPath
) )
467 aReturn
= xDirectAccess
->getByName(_rPath
);
469 else if (xHierarchyAccess
.is())
471 aReturn
= xHierarchyAccess
->getByHierarchicalName(_rPath
);
474 catch(NoSuchElementException
& e
)
476 OSL_UNUSED( e
); // make compiler happy
477 OSL_ENSURE(sal_False
,
478 ::rtl::OString("::getNodeValue: caught a NoSuchElementException while trying to open ")
479 += ::rtl::OString(e
.Message
.getStr(), e
.Message
.getLength(), RTL_TEXTENCODING_ASCII_US
)
480 += ::rtl::OString("!"));
484 // -----------------------------------------------------------------------------
485 void SAL_CALL
OPoolCollection::queryTermination( const EventObject
& /*Event*/ ) throw (::com::sun::star::frame::TerminationVetoException
, RuntimeException
)
488 // -----------------------------------------------------------------------------
489 void SAL_CALL
OPoolCollection::notifyTermination( const EventObject
& /*Event*/ ) throw (RuntimeException
)
493 // -----------------------------------------------------------------------------
494 void SAL_CALL
OPoolCollection::disposing( const EventObject
& Source
) throw (RuntimeException
)
496 MutexGuard
aGuard(m_aMutex
);
497 if ( m_xDesktop
== Source
.Source
)
505 Reference
<XPropertySet
> xProp(Source
.Source
,UNO_QUERY
);
506 if(Source
.Source
== m_xConfigNode
)
509 xProp
->removePropertyChangeListener(getEnablePoolingNodeName(),this);
510 m_xConfigNode
.clear();
512 else if ( xProp
.is() )
513 xProp
->removePropertyChangeListener(getEnableNodeName(),this);
515 catch(const Exception
&)
517 OSL_ENSURE(0,"Exception caught");
521 // -----------------------------------------------------------------------------
522 void SAL_CALL
OPoolCollection::propertyChange( const ::com::sun::star::beans::PropertyChangeEvent
& evt
) throw (RuntimeException
)
524 MutexGuard
aGuard(m_aMutex
);
525 if(evt
.Source
== m_xConfigNode
)
527 sal_Bool bEnabled
= sal_True
;
528 evt
.NewValue
>>= bEnabled
;
531 m_aDriverProxies
.clear();
532 m_aDriverProxies
= MapDriver2DriverRef();
533 OConnectionPools::iterator aIter
= m_aPools
.begin();
534 for(;aIter
!= m_aPools
.end();++aIter
)
536 aIter
->second
->clear(sal_False
);
537 aIter
->second
->release();
540 m_aPools
= OConnectionPools();
543 else if(evt
.Source
.is())
545 sal_Bool bEnabled
= sal_True
;
546 evt
.NewValue
>>= bEnabled
;
549 ::rtl::OUString sThisDriverName
;
550 getNodeValue(getDriverNameNodeName(),evt
.Source
) >>= sThisDriverName
;
551 // 1nd relase the driver
552 // look if we already have a proxy for this driver
553 MapDriver2DriverRefIterator aLookup
= m_aDriverProxies
.begin();
554 while( aLookup
!= m_aDriverProxies
.end())
556 MapDriver2DriverRefIterator aFind
= aLookup
;
557 Reference
<XServiceInfo
> xInfo(aLookup
->first
,UNO_QUERY
);
559 if(xInfo
.is() && xInfo
->getImplementationName() == sThisDriverName
)
560 m_aDriverProxies
.erase(aFind
);
563 // 2nd clear the connectionpool
564 OConnectionPools::iterator aFind
= m_aPools
.find(sThisDriverName
);
565 if(aFind
!= m_aPools
.end() && aFind
->second
)
567 aFind
->second
->clear(sal_False
);
568 aFind
->second
->release();
569 m_aPools
.erase(aFind
);
574 // -----------------------------------------------------------------------------
575 void OPoolCollection::clearDesktop()
577 clearConnectionPools(sal_True
);
578 if ( m_xDesktop
.is() )
579 m_xDesktop
->removeTerminateListener(this);
582 // -----------------------------------------------------------------------------