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 "KDriver.hxx"
28 #include "KDEInit.h"
29 #include "KConnection.hxx"
30
31 /** === begin UNO includes === **/
32 #include <com/sun/star/sdb/SQLContext.hpp>
33 #include <com/sun/star/lang/NullPointerException.hpp>
34 #include <com/sun/star/frame/XDesktop.hpp>
35 /** === end UNO includes === **/
36 #include <rtl/ustrbuf.hxx>
37 #include <tools/diagnose_ex.h>
38 #include "resource/kab_res.hrc"
39 #include "resource/sharedresources.hxx"
40
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::lang;
43 using namespace com::sun::star::beans;
44 using namespace com::sun::star::sdbc;
45 using namespace com::sun::star::sdb;
46 using namespace com::sun::star::frame;
47 using namespace connectivity::kab;
48
49 // =======================================================================
50 // = KabImplModule
51 // =======================================================================
52 // --------------------------------------------------------------------------------
KabImplModule(const Reference<XMultiServiceFactory> & _rxFactory)53 KabImplModule::KabImplModule( const Reference< XMultiServiceFactory >& _rxFactory )
54 :m_xORB(_rxFactory)
55 ,m_bAttemptedLoadModule(false)
56 ,m_bAttemptedInitialize(false)
57 ,m_hConnectorModule(NULL)
58 ,m_pConnectionFactoryFunc(NULL)
59 ,m_pApplicationInitFunc(NULL)
60 ,m_pApplicationShutdownFunc(NULL)
61 ,m_pKDEVersionCheckFunc(NULL)
62 {
63 if ( !m_xORB.is() )
64 throw NullPointerException();
65 }
66
67 // --------------------------------------------------------------------------------
isKDEPresent()68 bool KabImplModule::isKDEPresent()
69 {
70 if ( !impl_loadModule() )
71 return false;
72
73 return true;
74 }
75
76 // --------------------------------------------------------------------------------
matchKDEVersion()77 KabImplModule::KDEVersionType KabImplModule::matchKDEVersion()
78 {
79 OSL_PRECOND( m_pKDEVersionCheckFunc, "KabImplModule::matchKDEVersion: module not loaded!" );
80
81 int nVersionInfo = (*m_pKDEVersionCheckFunc)();
82 if ( nVersionInfo < 0 )
83 return eTooOld;
84 if ( nVersionInfo > 0 )
85 return eToNew;
86 return eSupported;
87 }
88
89 // --------------------------------------------------------------------------------
90 namespace
91 {
92 template< typename FUNCTION >
lcl_getFunctionFromModuleOrUnload(oslModule & _rModule,const sal_Char * _pAsciiSymbolName,FUNCTION & _rFunction)93 void lcl_getFunctionFromModuleOrUnload( oslModule& _rModule, const sal_Char* _pAsciiSymbolName, FUNCTION& _rFunction )
94 {
95 _rFunction = NULL;
96 if ( _rModule )
97 {
98 //
99 const ::rtl::OUString sSymbolName = ::rtl::OUString::createFromAscii( _pAsciiSymbolName );
100 _rFunction = (FUNCTION)( osl_getSymbol( _rModule, sSymbolName.pData ) );
101
102 if ( !_rFunction )
103 { // did not find the symbol
104 OSL_ENSURE( false, ::rtl::OString( "lcl_getFunctionFromModuleOrUnload: could not find the symbol " ) + ::rtl::OString( _pAsciiSymbolName ) );
105 osl_unloadModule( _rModule );
106 _rModule = NULL;
107 }
108 }
109 }
110 }
111
112 // --------------------------------------------------------------------------------
thisModule()113 extern "C" { void SAL_CALL thisModule() {} }
114
impl_loadModule()115 bool KabImplModule::impl_loadModule()
116 {
117 if ( m_bAttemptedLoadModule )
118 return ( m_hConnectorModule != NULL );
119 m_bAttemptedLoadModule = true;
120
121 OSL_ENSURE( !m_hConnectorModule && !m_pConnectionFactoryFunc && !m_pApplicationInitFunc && !m_pApplicationShutdownFunc && !m_pKDEVersionCheckFunc,
122 "KabImplModule::impl_loadModule: inconsistence: inconsistency (never attempted load before, but some values already set)!");
123
124 const ::rtl::OUString sModuleName = ::rtl::OUString::createFromAscii( SAL_MODULENAME( "kabdrv1" ) );
125 m_hConnectorModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, SAL_LOADMODULE_NOW ); // LAZY! #i61335#
126 OSL_ENSURE( m_hConnectorModule, "KabImplModule::impl_loadModule: could not load the implementation library!" );
127 if ( !m_hConnectorModule )
128 return false;
129
130 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "createKabConnection", m_pConnectionFactoryFunc );
131 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "initKApplication", m_pApplicationInitFunc );
132 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "shutdownKApplication", m_pApplicationShutdownFunc );
133 lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "matchKDEVersion", m_pKDEVersionCheckFunc );
134
135 if ( !m_hConnectorModule )
136 // one of the symbols did not exist
137 throw RuntimeException();
138
139 return true;
140 }
141
142 // --------------------------------------------------------------------------------
impl_unloadModule()143 void KabImplModule::impl_unloadModule()
144 {
145 OSL_PRECOND( m_hConnectorModule != NULL, "KabImplModule::impl_unloadModule: no module!" );
146
147 osl_unloadModule( m_hConnectorModule );
148 m_hConnectorModule = NULL;
149
150 m_pConnectionFactoryFunc = NULL;
151 m_pApplicationInitFunc = NULL;
152 m_pApplicationShutdownFunc = NULL;
153 m_pKDEVersionCheckFunc = NULL;
154
155 m_bAttemptedLoadModule = false;
156 }
157
158 // --------------------------------------------------------------------------------
init()159 void KabImplModule::init()
160 {
161 if ( !impl_loadModule() )
162 impl_throwNoKdeException();
163
164 // if we're not running on a supported version, throw
165 KabImplModule::KDEVersionType eKDEVersion = matchKDEVersion();
166
167 if ( eKDEVersion == eTooOld )
168 impl_throwKdeTooOldException();
169
170 if ( ( eKDEVersion == eToNew ) && !impl_doAllowNewKDEVersion() )
171 impl_throwKdeTooNewException();
172
173 if ( !m_bAttemptedInitialize )
174 {
175 m_bAttemptedInitialize = true;
176 (*m_pApplicationInitFunc)();
177 }
178 }
179
180 // --------------------------------------------------------------------------------
impl_doAllowNewKDEVersion()181 bool KabImplModule::impl_doAllowNewKDEVersion()
182 {
183 try
184 {
185 Reference< XMultiServiceFactory > xConfigProvider(
186 m_xORB->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) ) ),
187 UNO_QUERY_THROW );
188 Sequence< Any > aCreationArgs(1);
189 aCreationArgs[0] <<= PropertyValue(
190 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ),
191 0,
192 makeAny( KabDriver::impl_getConfigurationSettingsPath() ),
193 PropertyState_DIRECT_VALUE );
194 Reference< XPropertySet > xSettings( xConfigProvider->createInstanceWithArguments(
195 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationAccess" ) ),
196 aCreationArgs ),
197 UNO_QUERY_THROW );
198
199 sal_Bool bDisableCheck = sal_False;
200 xSettings->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableKDEMaximumVersionCheck" ) ) ) >>= bDisableCheck;
201
202 return bDisableCheck != sal_False;
203 }
204 catch( const Exception& )
205 {
206 DBG_UNHANDLED_EXCEPTION();
207 }
208 return false;
209 }
210
211 // --------------------------------------------------------------------------------
impl_throwNoKdeException()212 void KabImplModule::impl_throwNoKdeException()
213 {
214 ::connectivity::SharedResources aResources;
215 const ::rtl::OUString sError( aResources.getResourceString(
216 STR_NO_KDE_INST
217 ) );
218 impl_throwGenericSQLException( sError );
219 }
220
221 // --------------------------------------------------------------------------------
impl_throwKdeTooOldException()222 void KabImplModule::impl_throwKdeTooOldException()
223 {
224 ::connectivity::SharedResources aResources;
225 const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
226 STR_KDE_VERSION_TOO_OLD,
227 "$major$",::rtl::OUString::valueOf((sal_Int32)MIN_KDE_VERSION_MAJOR),
228 "$minor$",::rtl::OUString::valueOf((sal_Int32)MIN_KDE_VERSION_MINOR)
229 ) );
230 impl_throwGenericSQLException( sError );
231 }
232
233 // --------------------------------------------------------------------------------
impl_throwGenericSQLException(const::rtl::OUString & _rMessage)234 void KabImplModule::impl_throwGenericSQLException( const ::rtl::OUString& _rMessage )
235 {
236 SQLException aError;
237 aError.Message = _rMessage;
238 aError.SQLState = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "S1000" ) );
239 aError.ErrorCode = 0;
240 throw aError;
241 }
242
243 // --------------------------------------------------------------------------------
impl_throwKdeTooNewException()244 void KabImplModule::impl_throwKdeTooNewException()
245 {
246 ::connectivity::SharedResources aResources;
247
248 SQLException aError;
249 aError.Message = aResources.getResourceStringWithSubstitution(
250 STR_KDE_VERSION_TOO_NEW,
251 "$major$",::rtl::OUString::valueOf((sal_Int32)MIN_KDE_VERSION_MAJOR),
252 "$minor$",::rtl::OUString::valueOf((sal_Int32)MIN_KDE_VERSION_MINOR)
253 );
254 aError.SQLState = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "S1000" ) );
255 aError.ErrorCode = 0;
256
257 SQLContext aDetails;
258 ::rtl::OUStringBuffer aMessage;
259 aMessage.append( aResources.getResourceString(STR_KDE_VERSION_TOO_NEW_WORK_AROUND) );
260
261 aMessage.appendAscii( "Sub disableKDEMaxVersionCheck\n" );
262 aMessage.appendAscii( " BasicLibraries.LoadLibrary( \"Tools\" )\n" );
263
264 aMessage.appendAscii( " Dim configNode as Object\n" );
265 aMessage.appendAscii( " configNode = GetRegistryKeyContent( \"" );
266 aMessage.append( KabDriver::impl_getConfigurationSettingsPath() );
267 aMessage.appendAscii( "\", true )\n" );
268
269 aMessage.appendAscii( " configNode.DisableKDEMaximumVersionCheck = TRUE\n" );
270 aMessage.appendAscii( " configNode.commitChanges\n" );
271 aMessage.appendAscii( "End Sub\n" );
272
273 aDetails.Message = aMessage.makeStringAndClear();
274
275 aError.NextException <<= aDetails;
276
277 throw aError;
278 }
279
280 // --------------------------------------------------------------------------------
createConnection(KabDriver * _pDriver) const281 KabConnection* KabImplModule::createConnection( KabDriver* _pDriver ) const
282 {
283 OSL_PRECOND( m_hConnectorModule, "KabImplModule::createConnection: not initialized!" );
284
285 void* pUntypedConnection = (*m_pConnectionFactoryFunc)( _pDriver );
286 if ( !pUntypedConnection )
287 throw RuntimeException();
288
289 return static_cast< KabConnection* >( pUntypedConnection );
290 }
291
292 // --------------------------------------------------------------------------------
shutdown()293 void KabImplModule::shutdown()
294 {
295 if ( !m_hConnectorModule )
296 return;
297
298 (*m_pApplicationShutdownFunc)();
299 m_bAttemptedInitialize = false;
300
301 impl_unloadModule();
302 }
303
304 // =======================================================================
305 // = KabDriver
306 // =======================================================================
KabDriver(const Reference<::com::sun::star::lang::XMultiServiceFactory> & _rxFactory)307 KabDriver::KabDriver(
308 const Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory)
309 : KDriver_BASE(m_aMutex),
310 m_xMSFactory(_rxFactory),
311 m_aImplModule(_rxFactory)
312 {
313 if ( !m_xMSFactory.is() )
314 throw NullPointerException();
315
316 osl_incrementInterlockedCount( &m_refCount );
317 try
318 {
319 Reference< XDesktop > xDesktop(
320 m_xMSFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ) ),
321 UNO_QUERY_THROW );
322 xDesktop->addTerminateListener( this );
323 }
324 catch( const Exception& )
325 {
326 DBG_UNHANDLED_EXCEPTION();
327 }
328 osl_decrementInterlockedCount( &m_refCount );
329 }
330 // --------------------------------------------------------------------------------
disposing()331 void KabDriver::disposing()
332 {
333 ::osl::MutexGuard aGuard(m_aMutex);
334
335 // when driver will be destroied so all our connections have to be destroied as well
336 for (OWeakRefArray::iterator i = m_xConnections.begin(); m_xConnections.end() != i; ++i)
337 {
338 Reference< XComponent > xComp(i->get(), UNO_QUERY);
339 if (xComp.is())
340 xComp->dispose();
341 }
342 m_xConnections.clear();
343
344 WeakComponentImplHelperBase::disposing();
345 }
346 // static ServiceInfo
347 //------------------------------------------------------------------------------
getImplementationName_Static()348 rtl::OUString KabDriver::getImplementationName_Static( ) throw(RuntimeException)
349 {
350 return rtl::OUString::createFromAscii( impl_getAsciiImplementationName() );
351 }
352 //------------------------------------------------------------------------------
getSupportedServiceNames_Static()353 Sequence< ::rtl::OUString > KabDriver::getSupportedServiceNames_Static( ) throw (RuntimeException)
354 {
355 // which service is supported
356 // for more information @see com.sun.star.sdbc.Driver
357 Sequence< ::rtl::OUString > aSNS( 1 );
358 aSNS[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdbc.Driver");
359
360 return aSNS;
361 }
362 //------------------------------------------------------------------
getImplementationName()363 ::rtl::OUString SAL_CALL KabDriver::getImplementationName( ) throw(RuntimeException)
364 {
365 return getImplementationName_Static();
366 }
367 //------------------------------------------------------------------
supportsService(const::rtl::OUString & _rServiceName)368 sal_Bool SAL_CALL KabDriver::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException)
369 {
370 Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames());
371 const ::rtl::OUString* pSupported = aSupported.getConstArray();
372 const ::rtl::OUString* pEnd = pSupported + aSupported.getLength();
373
374 while (pSupported != pEnd && !pSupported->equals(_rServiceName))
375 ++pSupported;
376 return pSupported != pEnd;
377 }
378 //------------------------------------------------------------------
getSupportedServiceNames()379 Sequence< ::rtl::OUString > SAL_CALL KabDriver::getSupportedServiceNames( ) throw(RuntimeException)
380 {
381 return getSupportedServiceNames_Static();
382 }
383 // --------------------------------------------------------------------------------
connect(const::rtl::OUString & url,const Sequence<PropertyValue> & info)384 Reference< XConnection > SAL_CALL KabDriver::connect( const ::rtl::OUString& url, const Sequence< PropertyValue >& info ) throw(SQLException, RuntimeException)
385 {
386 ::osl::MutexGuard aGuard(m_aMutex);
387
388 m_aImplModule.init();
389
390 // create a new connection with the given properties and append it to our vector
391 KabConnection* pConnection = m_aImplModule.createConnection( this );
392 OSL_POSTCOND( pConnection, "KabDriver::connect: no connection has been created by the factory!" );
393
394 // by definition, the factory function returned an object which was acquired once
395 Reference< XConnection > xConnection = pConnection;
396 pConnection->release();
397
398 // late constructor call which can throw exception and allows a correct dtor call when so
399 pConnection->construct( url, info );
400
401 // remember it
402 m_xConnections.push_back( WeakReferenceHelper( *pConnection ) );
403
404 return xConnection;
405 }
406 // --------------------------------------------------------------------------------
acceptsURL(const::rtl::OUString & url)407 sal_Bool SAL_CALL KabDriver::acceptsURL( const ::rtl::OUString& url )
408 throw(SQLException, RuntimeException)
409 {
410 ::osl::MutexGuard aGuard(m_aMutex);
411
412 if ( !m_aImplModule.isKDEPresent() )
413 return sal_False;
414
415 // here we have to look whether we support this URL format
416 return (!url.compareTo(::rtl::OUString::createFromAscii("sdbc:address:kab:"), 16));
417 }
418 // --------------------------------------------------------------------------------
getPropertyInfo(const::rtl::OUString &,const Sequence<PropertyValue> &)419 Sequence< DriverPropertyInfo > SAL_CALL KabDriver::getPropertyInfo( const ::rtl::OUString&, const Sequence< PropertyValue >& ) throw(SQLException, RuntimeException)
420 {
421 // if you have something special to say, return it here :-)
422 return Sequence< DriverPropertyInfo >();
423 }
424 // --------------------------------------------------------------------------------
getMajorVersion()425 sal_Int32 SAL_CALL KabDriver::getMajorVersion( ) throw(RuntimeException)
426 {
427 return KAB_DRIVER_VERSION_MAJOR;
428 }
429 // --------------------------------------------------------------------------------
getMinorVersion()430 sal_Int32 SAL_CALL KabDriver::getMinorVersion( ) throw(RuntimeException)
431 {
432 return KAB_DRIVER_VERSION_MINOR;
433 }
434 // --------------------------------------------------------------------------------
queryTermination(const EventObject &)435 void SAL_CALL KabDriver::queryTermination( const EventObject& ) throw (TerminationVetoException, RuntimeException)
436 {
437 // nothing to do, nothing to veto
438 }
439 // --------------------------------------------------------------------------------
notifyTermination(const EventObject &)440 void SAL_CALL KabDriver::notifyTermination( const EventObject& ) throw (RuntimeException)
441 {
442 m_aImplModule.shutdown();
443 }
444 // --------------------------------------------------------------------------------
disposing(const EventObject &)445 void SAL_CALL KabDriver::disposing( const EventObject& ) throw (RuntimeException)
446 {
447 // not interested in (this is the disposing of the desktop, if any)
448 }
449 // --------------------------------------------------------------------------------
impl_getAsciiImplementationName()450 const sal_Char* KabDriver::impl_getAsciiImplementationName()
451 {
452 return "com.sun.star.comp.sdbc.kab.Driver";
453 // this name is referenced in the configuration and in the kab.xml
454 // Please be careful when changing it.
455 }
456 // --------------------------------------------------------------------------------
impl_getConfigurationSettingsPath()457 ::rtl::OUString KabDriver::impl_getConfigurationSettingsPath()
458 {
459 ::rtl::OUStringBuffer aPath;
460 aPath.appendAscii( "/org.openoffice.Office.DataAccess/DriverSettings/" );
461 aPath.appendAscii( "com.sun.star.comp.sdbc.kab.Driver" );
462 return aPath.makeStringAndClear();
463 }
464 // --------------------------------------------------------------------------------
Create(const Reference<XMultiServiceFactory> & _rxFactory)465 Reference< XInterface > SAL_CALL KabDriver::Create( const Reference< XMultiServiceFactory >& _rxFactory ) throw( Exception )
466 {
467 return *(new KabDriver(_rxFactory));
468 }
469
470