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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 68 bool KabImplModule::isKDEPresent() 69 { 70 if ( !impl_loadModule() ) 71 return false; 72 73 return true; 74 } 75 76 // -------------------------------------------------------------------------------- 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 > 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 // -------------------------------------------------------------------------------- 113 extern "C" { void SAL_CALL thisModule() {} } 114 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 281 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 // -------------------------------------------------------------------------------- 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 // ======================================================================= 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 // -------------------------------------------------------------------------------- 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 //------------------------------------------------------------------------------ 348 rtl::OUString KabDriver::getImplementationName_Static( ) throw(RuntimeException) 349 { 350 return rtl::OUString::createFromAscii( impl_getAsciiImplementationName() ); 351 } 352 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------ 363 ::rtl::OUString SAL_CALL KabDriver::getImplementationName( ) throw(RuntimeException) 364 { 365 return getImplementationName_Static(); 366 } 367 //------------------------------------------------------------------ 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 //------------------------------------------------------------------ 379 Sequence< ::rtl::OUString > SAL_CALL KabDriver::getSupportedServiceNames( ) throw(RuntimeException) 380 { 381 return getSupportedServiceNames_Static(); 382 } 383 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 425 sal_Int32 SAL_CALL KabDriver::getMajorVersion( ) throw(RuntimeException) 426 { 427 return KAB_DRIVER_VERSION_MAJOR; 428 } 429 // -------------------------------------------------------------------------------- 430 sal_Int32 SAL_CALL KabDriver::getMinorVersion( ) throw(RuntimeException) 431 { 432 return KAB_DRIVER_VERSION_MINOR; 433 } 434 // -------------------------------------------------------------------------------- 435 void SAL_CALL KabDriver::queryTermination( const EventObject& ) throw (TerminationVetoException, RuntimeException) 436 { 437 // nothing to do, nothing to veto 438 } 439 // -------------------------------------------------------------------------------- 440 void SAL_CALL KabDriver::notifyTermination( const EventObject& ) throw (RuntimeException) 441 { 442 m_aImplModule.shutdown(); 443 } 444 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 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 // -------------------------------------------------------------------------------- 465 Reference< XInterface > SAL_CALL KabDriver::Create( const Reference< XMultiServiceFactory >& _rxFactory ) throw( Exception ) 466 { 467 return *(new KabDriver(_rxFactory)); 468 } 469 470