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