1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "KDriver.hxx"
23 #include "KConnection.hxx"
24 #include "rtl/strbuf.hxx"
26 #include <com/sun/star/configuration/theDefaultProvider.hpp>
27 #include <com/sun/star/sdb/SQLContext.hpp>
28 #include <com/sun/star/lang/NullPointerException.hpp>
29 #include <com/sun/star/frame/Desktop.hpp>
30 #include <comphelper/processfactory.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <tools/diagnose_ex.h>
33 #include "resource/kab_res.hrc"
34 #include "resource/sharedresources.hxx"
36 using namespace com::sun::star::uno
;
37 using namespace com::sun::star::lang
;
38 using namespace com::sun::star::beans
;
39 using namespace com::sun::star::sdbc
;
40 using namespace com::sun::star::sdb
;
41 using namespace com::sun::star::frame
;
42 using namespace connectivity::kab
;
44 // =======================================================================
46 // =======================================================================
47 // --------------------------------------------------------------------------------
48 KabImplModule::KabImplModule( const Reference
< XComponentContext
>& _rxContext
)
49 :m_xContext(_rxContext
)
50 ,m_bAttemptedLoadModule(false)
51 ,m_bAttemptedInitialize(false)
52 ,m_hConnectorModule(NULL
)
53 ,m_pConnectionFactoryFunc(NULL
)
54 ,m_pApplicationInitFunc(NULL
)
55 ,m_pApplicationShutdownFunc(NULL
)
56 ,m_pKDEVersionCheckFunc(NULL
)
58 if ( !m_xContext
.is() )
59 throw NullPointerException();
62 // --------------------------------------------------------------------------------
63 bool KabImplModule::isKDEPresent()
65 if ( !impl_loadModule() )
71 // --------------------------------------------------------------------------------
72 KabImplModule::KDEVersionType
KabImplModule::matchKDEVersion()
74 OSL_PRECOND( m_pKDEVersionCheckFunc
, "KabImplModule::matchKDEVersion: module not loaded!" );
76 int nVersionInfo
= (*m_pKDEVersionCheckFunc
)();
77 if ( nVersionInfo
< 0 )
79 if ( nVersionInfo
> 0 )
84 // --------------------------------------------------------------------------------
87 template< typename FUNCTION
>
88 void lcl_getFunctionFromModuleOrUnload( oslModule
& _rModule
, const sal_Char
* _pAsciiSymbolName
, FUNCTION
& _rFunction
)
94 const OUString sSymbolName
= OUString::createFromAscii( _pAsciiSymbolName
);
95 _rFunction
= (FUNCTION
)( osl_getSymbol( _rModule
, sSymbolName
.pData
) );
98 { // did not find the symbol
100 aBuf
.append( "lcl_getFunctionFromModuleOrUnload: could not find the symbol " );
101 aBuf
.append( _pAsciiSymbolName
);
102 OSL_FAIL( aBuf
.makeStringAndClear().getStr() );
103 osl_unloadModule( _rModule
);
110 // --------------------------------------------------------------------------------
111 extern "C" { void SAL_CALL
thisModule() {} }
113 bool KabImplModule::impl_loadModule()
115 if ( m_bAttemptedLoadModule
)
116 return ( m_hConnectorModule
!= NULL
);
117 m_bAttemptedLoadModule
= true;
119 OSL_ENSURE( !m_hConnectorModule
&& !m_pConnectionFactoryFunc
&& !m_pApplicationInitFunc
&& !m_pApplicationShutdownFunc
&& !m_pKDEVersionCheckFunc
,
120 "KabImplModule::impl_loadModule: inconsistence: inconsistency (never attempted load before, but some values already set)!");
122 const OUString
sModuleName( SAL_MODULENAME( "kabdrv1" ));
123 m_hConnectorModule
= osl_loadModuleRelative( &thisModule
, sModuleName
.pData
, SAL_LOADMODULE_NOW
); // LAZY! #i61335#
124 OSL_ENSURE( m_hConnectorModule
, "KabImplModule::impl_loadModule: could not load the implementation library!" );
125 if ( !m_hConnectorModule
)
128 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule
, "createKabConnection", m_pConnectionFactoryFunc
);
129 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule
, "initKApplication", m_pApplicationInitFunc
);
130 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule
, "shutdownKApplication", m_pApplicationShutdownFunc
);
131 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule
, "matchKDEVersion", m_pKDEVersionCheckFunc
);
133 if ( !m_hConnectorModule
)
134 // one of the symbols did not exist
135 throw RuntimeException();
140 // --------------------------------------------------------------------------------
141 void KabImplModule::impl_unloadModule()
143 OSL_PRECOND( m_hConnectorModule
!= NULL
, "KabImplModule::impl_unloadModule: no module!" );
145 osl_unloadModule( m_hConnectorModule
);
146 m_hConnectorModule
= NULL
;
148 m_pConnectionFactoryFunc
= NULL
;
149 m_pApplicationInitFunc
= NULL
;
150 m_pApplicationShutdownFunc
= NULL
;
151 m_pKDEVersionCheckFunc
= NULL
;
153 m_bAttemptedLoadModule
= false;
156 // --------------------------------------------------------------------------------
157 void KabImplModule::init()
159 if ( !impl_loadModule() )
160 impl_throwNoKdeException();
162 // if we're not running on a supported version, throw
163 KabImplModule::KDEVersionType eKDEVersion
= matchKDEVersion();
165 if ( eKDEVersion
== eTooOld
)
166 impl_throwKdeTooOldException();
168 if ( ( eKDEVersion
== eToNew
) && !impl_doAllowNewKDEVersion() )
169 impl_throwKdeTooNewException();
171 if ( !m_bAttemptedInitialize
)
173 m_bAttemptedInitialize
= true;
174 (*m_pApplicationInitFunc
)();
178 // --------------------------------------------------------------------------------
179 bool KabImplModule::impl_doAllowNewKDEVersion()
183 Reference
< XMultiServiceFactory
> xConfigProvider(
184 com::sun::star::configuration::theDefaultProvider::get( m_xContext
) );
185 Sequence
< Any
> aCreationArgs(1);
186 aCreationArgs
[0] <<= PropertyValue(
187 OUString( "nodepath" ),
189 makeAny( KabDriver::impl_getConfigurationSettingsPath() ),
190 PropertyState_DIRECT_VALUE
);
191 Reference
< XPropertySet
> xSettings( xConfigProvider
->createInstanceWithArguments(
192 OUString( "com.sun.star.configuration.ConfigurationAccess" ),
196 sal_Bool bDisableCheck
= sal_False
;
197 xSettings
->getPropertyValue( OUString( "DisableKDEMaximumVersionCheck" ) ) >>= bDisableCheck
;
199 return bDisableCheck
!= sal_False
;
201 catch( const Exception
& )
203 DBG_UNHANDLED_EXCEPTION();
208 // --------------------------------------------------------------------------------
209 void KabImplModule::impl_throwNoKdeException()
211 ::connectivity::SharedResources aResources
;
212 const OUString
sError( aResources
.getResourceString(
215 impl_throwGenericSQLException( sError
);
218 // --------------------------------------------------------------------------------
219 void KabImplModule::impl_throwKdeTooOldException()
221 ::connectivity::SharedResources aResources
;
222 const OUString
sError( aResources
.getResourceStringWithSubstitution(
223 STR_KDE_VERSION_TOO_OLD
,
224 "$major$",OUString::valueOf((sal_Int32
)MIN_KDE_VERSION_MAJOR
),
225 "$minor$",OUString::valueOf((sal_Int32
)MIN_KDE_VERSION_MINOR
)
227 impl_throwGenericSQLException( sError
);
230 // --------------------------------------------------------------------------------
231 void KabImplModule::impl_throwGenericSQLException( const OUString
& _rMessage
)
234 aError
.Message
= _rMessage
;
235 aError
.SQLState
= OUString( "S1000" );
236 aError
.ErrorCode
= 0;
240 // --------------------------------------------------------------------------------
241 void KabImplModule::impl_throwKdeTooNewException()
243 ::connectivity::SharedResources aResources
;
246 aError
.Message
= aResources
.getResourceStringWithSubstitution(
247 STR_KDE_VERSION_TOO_NEW
,
248 "$major$",OUString::valueOf((sal_Int32
)MIN_KDE_VERSION_MAJOR
),
249 "$minor$",OUString::valueOf((sal_Int32
)MIN_KDE_VERSION_MINOR
)
251 aError
.SQLState
= OUString( "S1000" );
252 aError
.ErrorCode
= 0;
255 OUStringBuffer aMessage
;
256 aMessage
.append( aResources
.getResourceString(STR_KDE_VERSION_TOO_NEW_WORK_AROUND
) );
258 aMessage
.appendAscii( "Sub disableKDEMaxVersionCheck\n" );
259 aMessage
.appendAscii( " BasicLibraries.LoadLibrary( \"Tools\" )\n" );
261 aMessage
.appendAscii( " Dim configNode as Object\n" );
262 aMessage
.appendAscii( " configNode = GetRegistryKeyContent( \"" );
263 aMessage
.append( KabDriver::impl_getConfigurationSettingsPath() );
264 aMessage
.appendAscii( "\", true )\n" );
266 aMessage
.appendAscii( " configNode.DisableKDEMaximumVersionCheck = TRUE\n" );
267 aMessage
.appendAscii( " configNode.commitChanges\n" );
268 aMessage
.appendAscii( "End Sub\n" );
270 aDetails
.Message
= aMessage
.makeStringAndClear();
272 aError
.NextException
<<= aDetails
;
277 // --------------------------------------------------------------------------------
278 KabConnection
* KabImplModule::createConnection( KabDriver
* _pDriver
) const
280 OSL_PRECOND( m_hConnectorModule
, "KabImplModule::createConnection: not initialized!" );
282 void* pUntypedConnection
= (*m_pConnectionFactoryFunc
)( _pDriver
);
283 if ( !pUntypedConnection
)
284 throw RuntimeException();
286 return static_cast< KabConnection
* >( pUntypedConnection
);
289 // --------------------------------------------------------------------------------
290 void KabImplModule::shutdown()
292 if ( !m_hConnectorModule
)
295 (*m_pApplicationShutdownFunc
)();
296 m_bAttemptedInitialize
= false;
301 // =======================================================================
303 // =======================================================================
304 KabDriver::KabDriver(
305 const Reference
< ::com::sun::star::uno::XComponentContext
>& _rxContext
)
306 : KDriver_BASE(m_aMutex
),
307 m_xContext(_rxContext
),
308 m_aImplModule(_rxContext
)
310 if ( !m_xContext
.is() )
311 throw NullPointerException();
313 osl_atomic_increment( &m_refCount
);
316 Reference
< XDesktop2
> xDesktop
= Desktop::create( m_xContext
);
317 xDesktop
->addTerminateListener( this );
319 catch( const Exception
& )
321 DBG_UNHANDLED_EXCEPTION();
323 osl_atomic_decrement( &m_refCount
);
325 // --------------------------------------------------------------------------------
326 void KabDriver::disposing()
328 ::osl::MutexGuard
aGuard(m_aMutex
);
330 // when driver will be destroied so all our connections have to be destroied as well
331 for (OWeakRefArray::iterator i
= m_xConnections
.begin(); m_xConnections
.end() != i
; ++i
)
333 Reference
< XComponent
> xComp(i
->get(), UNO_QUERY
);
337 m_xConnections
.clear();
339 WeakComponentImplHelperBase::disposing();
341 // static ServiceInfo
342 //------------------------------------------------------------------------------
343 OUString
KabDriver::getImplementationName_Static( ) throw(RuntimeException
)
345 return OUString::createFromAscii( impl_getAsciiImplementationName() );
347 //------------------------------------------------------------------------------
348 Sequence
< OUString
> KabDriver::getSupportedServiceNames_Static( ) throw (RuntimeException
)
350 // which service is supported
351 // for more information @see com.sun.star.sdbc.Driver
352 Sequence
< OUString
> aSNS( 1 );
353 aSNS
[0] = OUString("com.sun.star.sdbc.Driver");
357 //------------------------------------------------------------------
358 OUString SAL_CALL
KabDriver::getImplementationName( ) throw(RuntimeException
)
360 return getImplementationName_Static();
362 //------------------------------------------------------------------
363 sal_Bool SAL_CALL
KabDriver::supportsService( const OUString
& _rServiceName
) throw(RuntimeException
)
365 Sequence
< OUString
> aSupported(getSupportedServiceNames());
366 const OUString
* pSupported
= aSupported
.getConstArray();
367 const OUString
* pEnd
= pSupported
+ aSupported
.getLength();
369 while (pSupported
!= pEnd
&& !pSupported
->equals(_rServiceName
))
371 return pSupported
!= pEnd
;
373 //------------------------------------------------------------------
374 Sequence
< OUString
> SAL_CALL
KabDriver::getSupportedServiceNames( ) throw(RuntimeException
)
376 return getSupportedServiceNames_Static();
378 // --------------------------------------------------------------------------------
379 Reference
< XConnection
> SAL_CALL
KabDriver::connect( const OUString
& url
, const Sequence
< PropertyValue
>& info
) throw(SQLException
, RuntimeException
)
381 ::osl::MutexGuard
aGuard(m_aMutex
);
383 m_aImplModule
.init();
385 // create a new connection with the given properties and append it to our vector
386 KabConnection
* pConnection
= m_aImplModule
.createConnection( this );
387 OSL_POSTCOND( pConnection
, "KabDriver::connect: no connection has been created by the factory!" );
389 // by definition, the factory function returned an object which was acquired once
390 Reference
< XConnection
> xConnection
= pConnection
;
391 pConnection
->release();
393 // late constructor call which can throw exception and allows a correct dtor call when so
394 pConnection
->construct( url
, info
);
397 m_xConnections
.push_back( WeakReferenceHelper( *pConnection
) );
401 // --------------------------------------------------------------------------------
402 sal_Bool SAL_CALL
KabDriver::acceptsURL( const OUString
& url
)
403 throw(SQLException
, RuntimeException
)
405 ::osl::MutexGuard
aGuard(m_aMutex
);
407 if ( !m_aImplModule
.isKDEPresent() )
410 // here we have to look whether we support this URL format
411 return url
.startsWith("sdbc:address:kab:");
413 // --------------------------------------------------------------------------------
414 Sequence
< DriverPropertyInfo
> SAL_CALL
KabDriver::getPropertyInfo( const OUString
&, const Sequence
< PropertyValue
>& ) throw(SQLException
, RuntimeException
)
416 // if you have something special to say, return it here :-)
417 return Sequence
< DriverPropertyInfo
>();
419 // --------------------------------------------------------------------------------
420 sal_Int32 SAL_CALL
KabDriver::getMajorVersion( ) throw(RuntimeException
)
422 return KAB_DRIVER_VERSION_MAJOR
;
424 // --------------------------------------------------------------------------------
425 sal_Int32 SAL_CALL
KabDriver::getMinorVersion( ) throw(RuntimeException
)
427 return KAB_DRIVER_VERSION_MINOR
;
429 // --------------------------------------------------------------------------------
430 void SAL_CALL
KabDriver::queryTermination( const EventObject
& ) throw (TerminationVetoException
, RuntimeException
)
432 // nothing to do, nothing to veto
434 // --------------------------------------------------------------------------------
435 void SAL_CALL
KabDriver::notifyTermination( const EventObject
& ) throw (RuntimeException
)
437 m_aImplModule
.shutdown();
439 // --------------------------------------------------------------------------------
440 void SAL_CALL
KabDriver::disposing( const EventObject
& ) throw (RuntimeException
)
442 // not interested in (this is the disposing of the desktop, if any)
444 // --------------------------------------------------------------------------------
445 const sal_Char
* KabDriver::impl_getAsciiImplementationName()
447 return "com.sun.star.comp.sdbc.kab.Driver";
448 // this name is referenced in the configuration and in the kab.xml
449 // Please be careful when changing it.
451 // --------------------------------------------------------------------------------
452 OUString
KabDriver::impl_getConfigurationSettingsPath()
454 OUStringBuffer aPath
;
455 aPath
.appendAscii( "/org.openoffice.Office.DataAccess/DriverSettings/" );
456 aPath
.appendAscii( "com.sun.star.comp.sdbc.kab.Driver" );
457 return aPath
.makeStringAndClear();
459 // --------------------------------------------------------------------------------
460 Reference
< XInterface
> SAL_CALL
KabDriver::Create( const Reference
< XMultiServiceFactory
>& _rxFactory
) throw( Exception
)
462 return *(new KabDriver( comphelper::getComponentContext(_rxFactory
)));
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */