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 "java/sql/Connection.hxx" 32 #include "java/lang/Class.hxx" 33 #include "java/tools.hxx" 34 #include "java/ContextClassLoader.hxx" 35 #include "java/sql/DatabaseMetaData.hxx" 36 #include "java/sql/JStatement.hxx" 37 #include "java/sql/Driver.hxx" 38 #include "java/sql/PreparedStatement.hxx" 39 #include "java/sql/CallableStatement.hxx" 40 #include "java/sql/SQLWarning.hxx" 41 #include <com/sun/star/lang/DisposedException.hpp> 42 #include <com/sun/star/sdbc/SQLWarning.hpp> 43 #include <com/sun/star/sdbc/SQLWarning.hpp> 44 #include <com/sun/star/beans/NamedValue.hpp> 45 #include "connectivity/sqlparse.hxx" 46 #include "connectivity/dbexception.hxx" 47 #include "java/util/Property.hxx" 48 #include "java/LocalRef.hxx" 49 #include "resource/jdbc_log.hrc" 50 #include "com/sun/star/uno/XComponentContext.hpp" 51 #include "jvmaccess/classpath.hxx" 52 #include <comphelper/namedvaluecollection.hxx> 53 #include <rtl/ustrbuf.hxx> 54 #include <jni.h> 55 #include "resource/common_res.hrc" 56 #include <unotools/confignode.hxx> 57 58 #include <list> 59 #include <memory> 60 61 using namespace connectivity; 62 using namespace connectivity::jdbc; 63 using namespace ::com::sun::star::uno; 64 using namespace ::com::sun::star::beans; 65 using namespace ::com::sun::star::sdbc; 66 using namespace ::com::sun::star::container; 67 using namespace ::com::sun::star::lang; 68 69 namespace { 70 71 struct ClassMapEntry { 72 ClassMapEntry( 73 rtl::OUString const & theClassPath, rtl::OUString const & theClassName): 74 classPath(theClassPath), className(theClassName), classLoader(NULL), 75 classObject(NULL) {} 76 77 rtl::OUString classPath; 78 rtl::OUString className; 79 jweak classLoader; 80 jweak classObject; 81 }; 82 83 typedef std::list< ClassMapEntry > ClassMap; 84 85 struct ClassMapData { 86 osl::Mutex mutex; 87 88 ClassMap map; 89 }; 90 91 struct ClassMapDataInit { 92 ClassMapData * operator()() { 93 static ClassMapData instance; 94 return &instance; 95 } 96 }; 97 98 template < typename T > 99 bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local ) 100 { 101 _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) ); 102 103 if ( !_inout_local.is() ) 104 { 105 if ( _inout_local.env().ExceptionCheck()) 106 { 107 return false; 108 } 109 else if ( _weak != NULL ) 110 { 111 _inout_local.env().DeleteWeakGlobalRef( _weak ); 112 _weak = NULL; 113 } 114 } 115 return true; 116 } 117 118 // Load a class. A map from pairs of (classPath, name) to pairs of weak Java 119 // references to (ClassLoader, Class) is maintained, so that a class is only 120 // loaded once. 121 // 122 // It may happen that the weak reference to the ClassLoader becomes null while 123 // the reference to the Class remains non-null (in case the Class was actually 124 // loaded by some parent of the ClassLoader), in which case the ClassLoader is 125 // resurrected (which cannot cause any classes to be loaded multiple times, as 126 // the ClassLoader is no longer reachable, so no classes it has ever loaded are 127 // still reachable). 128 // 129 // Similarly, it may happen that the weak reference to the Class becomes null 130 // while the reference to the ClassLoader remains non-null, in which case the 131 // Class is simply re-loaded. 132 // 133 // This code is close to the implementation of jvmaccess::ClassPath::loadClass 134 // in jvmaccess/classpath.hxx, but not close enough to avoid the duplication. 135 // 136 // If false is returned, a (still pending) JNI exception occurred. 137 bool loadClass( 138 Reference< XComponentContext > const & context, JNIEnv& environment, 139 rtl::OUString const & classPath, rtl::OUString const & name, 140 LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr) 141 { 142 OSL_ASSERT(classLoaderPtr != NULL); 143 // For any jweak entries still present in the map upon destruction, 144 // DeleteWeakGlobalRef is not called (which is a leak): 145 ClassMapData * d = 146 rtl_Instance< ClassMapData, ClassMapDataInit, osl::MutexGuard, 147 osl::GetGlobalMutex >::create( 148 ClassMapDataInit(), osl::GetGlobalMutex()); 149 osl::MutexGuard g(d->mutex); 150 ClassMap::iterator i(d->map.begin()); 151 LocalRef< jobject > cloader(environment); 152 LocalRef< jclass > cl(environment); 153 // Prune dangling weak references from the list while searching for a match, 154 // so that the list cannot grow unbounded: 155 for (; i != d->map.end();) 156 { 157 LocalRef< jobject > classLoader( environment ); 158 if ( !getLocalFromWeakRef( i->classLoader, classLoader ) ) 159 return false; 160 161 LocalRef< jclass > classObject( environment ); 162 if ( !getLocalFromWeakRef( i->classObject, classObject ) ) 163 return false; 164 165 if ( !classLoader.is() && !classObject.is() ) 166 { 167 i = d->map.erase(i); 168 } 169 else if ( i->classPath == classPath && i->className == name ) 170 { 171 cloader.set( classLoader.release() ); 172 cl.set( classObject.release() ); 173 break; 174 } 175 else 176 { 177 ++i; 178 } 179 } 180 if ( !cloader.is() || !cl.is() ) 181 { 182 if ( i == d->map.end() ) 183 { 184 // Push a new ClassMapEntry (which can potentially fail) before 185 // loading the class, so that it never happens that a class is 186 // loaded but not added to the map (which could have effects on the 187 // JVM that are not easily undone). If the pushed ClassMapEntry is 188 // not used after all (return false, etc.) it will be pruned on next 189 // call because its classLoader/classObject are null: 190 d->map.push_front( ClassMapEntry( classPath, name ) ); 191 i = d->map.begin(); 192 } 193 194 LocalRef< jclass > clClass( environment ); 195 clClass.set( environment.FindClass( "java/net/URLClassLoader" ) ); 196 if ( !clClass.is() ) 197 return false; 198 199 jweak wcloader = NULL; 200 if (!cloader.is()) 201 { 202 jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) ); 203 if (ctorLoader == NULL) 204 return false; 205 206 LocalRef< jobjectArray > arr( environment ); 207 arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) ); 208 if ( !arr.is() ) 209 return false; 210 211 jvalue arg; 212 arg.l = arr.get(); 213 cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) ); 214 if ( !cloader.is() ) 215 return false; 216 217 wcloader = environment.NewWeakGlobalRef( cloader.get() ); 218 if ( wcloader == NULL ) 219 return false; 220 } 221 222 jweak wcl = NULL; 223 if ( !cl.is() ) 224 { 225 jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) ); 226 if ( methLoadClass == NULL ) 227 return false; 228 229 LocalRef< jstring > str( environment ); 230 str.set( convertwchar_tToJavaString( &environment, name ) ); 231 if ( !str.is() ) 232 return false; 233 234 jvalue arg; 235 arg.l = str.get(); 236 cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) ); 237 if ( !cl.is() ) 238 return false; 239 240 wcl = environment.NewWeakGlobalRef( cl.get() ); 241 if ( wcl == NULL ) 242 return false; 243 } 244 245 if ( wcloader != NULL) 246 { 247 i->classLoader = wcloader; 248 } 249 if ( wcl != NULL ) 250 { 251 i->classObject = wcl; 252 } 253 } 254 255 classLoaderPtr->set( cloader.release() ); 256 classPtr->set( cl.release() ); 257 return true; 258 } 259 260 } 261 262 //------------------------------------------------------------------------------ 263 IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection"); 264 //------------------------------------------------------------------------------ 265 //************************************************************** 266 //************ Class: java.sql.Connection 267 //************************************************************** 268 jclass java_sql_Connection::theClass = 0; 269 270 java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver ) 271 :java_lang_Object( _rDriver.getContext().getLegacyServiceFactory() ) 272 ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this) 273 ,m_pDriver( &_rDriver ) 274 ,m_pDriverobject(NULL) 275 ,m_pDriverClassLoader() 276 ,m_Driver_theClass(NULL) 277 ,m_aLogger( _rDriver.getLogger() ) 278 ,m_bParameterSubstitution(sal_False) 279 ,m_bIgnoreDriverPrivileges(sal_True) 280 ,m_bIgnoreCurrency(sal_False) 281 { 282 } 283 // ----------------------------------------------------------------------------- 284 java_sql_Connection::~java_sql_Connection() 285 { 286 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(); 287 if ( xTest.is() ) 288 { 289 SDBThreadAttach t; 290 clearObject(*t.pEnv); 291 292 { 293 if ( m_pDriverobject ) 294 t.pEnv->DeleteGlobalRef( m_pDriverobject ); 295 m_pDriverobject = NULL; 296 if ( m_Driver_theClass ) 297 t.pEnv->DeleteGlobalRef( m_Driver_theClass ); 298 m_Driver_theClass = NULL; 299 } 300 t.releaseRef(); 301 } 302 } 303 //----------------------------------------------------------------------------- 304 void SAL_CALL java_sql_Connection::release() throw() 305 { 306 relase_ChildImpl(); 307 } 308 //------------------------------------------------------------------------------ 309 void java_sql_Connection::disposing() 310 { 311 ::osl::MutexGuard aGuard(m_aMutex); 312 313 m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION ); 314 315 dispose_ChildImpl(); 316 java_sql_Connection_BASE::disposing(); 317 318 if ( object ) 319 { 320 static jmethodID mID(NULL); 321 callVoidMethod("close",mID); 322 } 323 } 324 // ------------------------------------------------------------------------- 325 jclass java_sql_Connection::getMyClass() const 326 { 327 // die Klasse muss nur einmal geholt werden, daher statisch 328 if( !theClass ) 329 theClass = findMyClass("java/sql/Connection"); 330 return theClass; 331 } 332 333 // ------------------------------------------------------------------------- 334 ::rtl::OUString SAL_CALL java_sql_Connection::getCatalog( ) throw(SQLException, RuntimeException) 335 { 336 ::osl::MutexGuard aGuard( m_aMutex ); 337 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 338 339 static jmethodID mID(NULL); 340 return callStringMethod("getCatalog",mID); 341 } 342 // ------------------------------------------------------------------------- 343 Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException) 344 { 345 ::osl::MutexGuard aGuard( m_aMutex ); 346 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 347 348 349 Reference< XDatabaseMetaData > xMetaData = m_xMetaData; 350 if(!xMetaData.is()) 351 { 352 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); 353 static jmethodID mID(NULL); 354 jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID); 355 if(out) 356 { 357 xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this ); 358 m_xMetaData = xMetaData; 359 } 360 } 361 362 return xMetaData; 363 } 364 // ------------------------------------------------------------------------- 365 void SAL_CALL java_sql_Connection::close( ) throw(SQLException, RuntimeException) 366 { 367 dispose(); 368 } 369 // ------------------------------------------------------------------------- 370 void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException) 371 { 372 static jmethodID mID(NULL); 373 callVoidMethod("commit",mID); 374 } 375 // ------------------------------------------------------------------------- 376 sal_Bool SAL_CALL java_sql_Connection::isClosed( ) throw(SQLException, RuntimeException) 377 { 378 ::osl::MutexGuard aGuard( m_aMutex ); 379 380 static jmethodID mID(NULL); 381 return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed; 382 } 383 // ------------------------------------------------------------------------- 384 sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) throw(SQLException, RuntimeException) 385 { 386 ::osl::MutexGuard aGuard( m_aMutex ); 387 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 388 static jmethodID mID(NULL); 389 return callBooleanMethod( "isReadOnly", mID ); 390 } 391 // ------------------------------------------------------------------------- 392 void SAL_CALL java_sql_Connection::setCatalog( const ::rtl::OUString& catalog ) throw(SQLException, RuntimeException) 393 { 394 static jmethodID mID(NULL); 395 callVoidMethodWithStringArg("setCatalog",mID,catalog); 396 } 397 // ------------------------------------------------------------------------- 398 void SAL_CALL java_sql_Connection::rollback( ) throw(SQLException, RuntimeException) 399 { 400 static jmethodID mID(NULL); 401 callVoidMethod("rollback",mID); 402 } 403 // ------------------------------------------------------------------------- 404 sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException) 405 { 406 static jmethodID mID(NULL); 407 return callBooleanMethod( "getAutoCommit", mID ); 408 } 409 // ------------------------------------------------------------------------- 410 void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException) 411 { 412 static jmethodID mID(NULL); 413 callVoidMethodWithBoolArg("setReadOnly",mID,readOnly); 414 } 415 // ------------------------------------------------------------------------- 416 void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException) 417 { 418 static jmethodID mID(NULL); 419 callVoidMethodWithBoolArg("setAutoCommit",mID,autoCommit); 420 } 421 // ------------------------------------------------------------------------- 422 Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) throw(SQLException, RuntimeException) 423 { 424 ::osl::MutexGuard aGuard( m_aMutex ); 425 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 426 427 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); 428 static jmethodID mID(NULL); 429 /*jobject out = */callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID); 430 // ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!! 431 return 0;// ? 0 : Map2XNameAccess( t.pEnv, out ); 432 } 433 // ------------------------------------------------------------------------- 434 void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException) 435 { 436 ::osl::MutexGuard aGuard( m_aMutex ); 437 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 438 439 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this ); 440 } 441 442 // ------------------------------------------------------------------------- 443 sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException) 444 { 445 ::osl::MutexGuard aGuard( m_aMutex ); 446 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 447 448 static jmethodID mID(NULL); 449 return callIntMethod("getTransactionIsolation",mID); 450 } 451 // ------------------------------------------------------------------------- 452 void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException) 453 { 454 ::osl::MutexGuard aGuard( m_aMutex ); 455 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 456 457 static jmethodID mID(NULL); 458 callVoidMethodWithIntArg("setTransactionIsolation",mID,level); 459 } 460 // ------------------------------------------------------------------------- 461 Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException) 462 { 463 ::osl::MutexGuard aGuard( m_aMutex ); 464 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 465 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT ); 466 467 SDBThreadAttach t; 468 java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this ); 469 Reference< XStatement > xStmt = pStatement; 470 m_aStatements.push_back( WeakReferenceHelper( xStmt ) ); 471 472 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() ); 473 return xStmt; 474 } 475 // ----------------------------------------------------------------------------- 476 ::rtl::OUString java_sql_Connection::transFormPreparedStatement(const ::rtl::OUString& _sSQL) 477 { 478 ::rtl::OUString sSqlStatement = _sSQL; 479 if ( m_bParameterSubstitution ) 480 { 481 try 482 { 483 OSQLParser aParser( m_pDriver->getContext().getLegacyServiceFactory() ); 484 ::rtl::OUString sErrorMessage; 485 ::rtl::OUString sNewSql; 486 OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL); 487 if(pNode) 488 { // special handling for parameters 489 OSQLParseNode::substituteParameterNames(pNode); 490 pNode->parseNodeToStr( sNewSql, this ); 491 delete pNode; 492 sSqlStatement = sNewSql; 493 } 494 } 495 catch(const Exception&) 496 { 497 } 498 } 499 return sSqlStatement; 500 } 501 // ------------------------------------------------------------------------- 502 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) 503 { 504 ::osl::MutexGuard aGuard( m_aMutex ); 505 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 506 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql ); 507 508 SDBThreadAttach t; 509 ::rtl::OUString sSqlStatement = sql; 510 sSqlStatement = transFormPreparedStatement( sSqlStatement ); 511 512 java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement ); 513 Reference< XPreparedStatement > xReturn( pStatement ); 514 m_aStatements.push_back(WeakReferenceHelper(xReturn)); 515 516 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() ); 517 return xReturn; 518 } 519 // ------------------------------------------------------------------------- 520 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) 521 { 522 ::osl::MutexGuard aGuard( m_aMutex ); 523 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 524 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql ); 525 526 SDBThreadAttach t; 527 ::rtl::OUString sSqlStatement = sql; 528 sSqlStatement = transFormPreparedStatement( sSqlStatement ); 529 530 java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement ); 531 Reference< XPreparedStatement > xStmt( pStatement ); 532 m_aStatements.push_back(WeakReferenceHelper(xStmt)); 533 534 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() ); 535 return xStmt; 536 } 537 // ------------------------------------------------------------------------- 538 ::rtl::OUString SAL_CALL java_sql_Connection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException) 539 { 540 ::osl::MutexGuard aGuard( m_aMutex ); 541 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 542 543 ::rtl::OUString aStr; 544 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!"); 545 { 546 547 // temporaere Variable initialisieren 548 static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;"; 549 static const char * cMethodName = "nativeSQL"; 550 // Java-Call absetzen 551 static jmethodID mID(NULL); 552 obtainMethodId(t.pEnv, cMethodName,cSignature, mID); 553 // Parameter konvertieren 554 jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql)); 555 556 jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() ); 557 aStr = JavaString2String(t.pEnv, (jstring)out ); 558 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); 559 } //t.pEnv 560 561 m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr ); 562 563 return aStr; 564 } 565 // ------------------------------------------------------------------------- 566 void SAL_CALL java_sql_Connection::clearWarnings( ) throw(SQLException, RuntimeException) 567 { 568 static jmethodID mID(NULL); 569 callVoidMethod("clearWarnings",mID); 570 } 571 // ------------------------------------------------------------------------- 572 Any SAL_CALL java_sql_Connection::getWarnings( ) throw(SQLException, RuntimeException) 573 { 574 ::osl::MutexGuard aGuard( m_aMutex ); 575 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); 576 577 SDBThreadAttach t; 578 static jmethodID mID(NULL); 579 jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID); 580 // ACHTUNG: der Aufrufer wird Eigentuemer des zurueckgelieferten Zeigers !!! 581 if( out ) 582 { 583 java_sql_SQLWarning_BASE warn_base(t.pEnv, out); 584 SQLException aAsException( static_cast< starsdbc::SQLException >( java_sql_SQLWarning( warn_base, *this ) ) ); 585 586 // translate to warning 587 SQLWarning aWarning; 588 aWarning.Context = aAsException.Context; 589 aWarning.Message = aAsException.Message; 590 aWarning.SQLState = aAsException.SQLState; 591 aWarning.ErrorCode = aAsException.ErrorCode; 592 aWarning.NextException = aAsException.NextException; 593 594 return makeAny( aWarning ); 595 } 596 597 return Any(); 598 } 599 600 // ----------------------------------------------------------------------------- 601 namespace 602 { 603 ::rtl::OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const ::rtl::OUString& _rDriverClass, const ::rtl::OUString& _rDriverClassPath ) 604 { 605 ::rtl::OUString sError1( _aResource.getResourceStringWithSubstitution( 606 STR_NO_CLASSNAME, 607 "$classname$", _rDriverClass 608 ) ); 609 if ( _rDriverClassPath.getLength() ) 610 { 611 const ::rtl::OUString sError2( _aResource.getResourceStringWithSubstitution( 612 STR_NO_CLASSNAME_PATH, 613 "$classpath$", _rDriverClassPath 614 ) ); 615 sError1 += sError2; 616 } // if ( _rDriverClassPath.getLength() ) 617 return sError1; 618 } 619 } 620 621 // ----------------------------------------------------------------------------- 622 namespace 623 { 624 bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger, 625 JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties ) 626 { 627 if ( _rSystemProperties.getLength() == 0 ) 628 // nothing to do 629 return true; 630 631 LocalRef< jclass > systemClass( _rEnv ); 632 jmethodID nSetPropertyMethodID = 0; 633 // retrieve the java.lang.System class 634 systemClass.set( _rEnv.FindClass( "java/lang/System" ) ); 635 if ( systemClass.is() ) 636 { 637 nSetPropertyMethodID = _rEnv.GetStaticMethodID( 638 systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" ); 639 } 640 641 if ( nSetPropertyMethodID == 0 ) 642 return false; 643 644 for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray(); 645 pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength(); 646 ++pSystemProp 647 ) 648 { 649 ::rtl::OUString sValue; 650 OSL_VERIFY( pSystemProp->Value >>= sValue ); 651 652 _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue ); 653 654 LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) ); 655 LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) ); 656 657 _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() ); 658 LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() ); 659 if ( throwable.is() ) 660 return false; 661 } 662 663 return true; 664 } 665 } 666 667 // ----------------------------------------------------------------------------- 668 void java_sql_Connection::loadDriverFromProperties( const ::rtl::OUString& _sDriverClass, const ::rtl::OUString& _sDriverClassPath, 669 const Sequence< NamedValue >& _rSystemProperties ) 670 { 671 // contains the statement which should be used when query for automatically generated values 672 ::rtl::OUString sGeneratedValueStatement; 673 // set to <TRUE/> when we should allow to query for generated values 674 sal_Bool bAutoRetrievingEnabled = sal_False; 675 676 // first try if the jdbc driver is alraedy registered at the driver manager 677 SDBThreadAttach t; 678 try 679 { 680 if ( !object ) 681 { 682 if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) ) 683 ThrowLoggedSQLException( getLogger(), t.pEnv, *this ); 684 685 m_pDriverClassLoader.reset(); 686 687 // here I try to find the class for jdbc driver 688 java_sql_SQLException_BASE::st_getMyClass(); 689 java_lang_Throwable::st_getMyClass(); 690 691 if ( !_sDriverClass.getLength() ) 692 { 693 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS ); 694 ::dbtools::throwGenericSQLException( 695 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), 696 *this 697 ); 698 } 699 else 700 { 701 m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass ); 702 // the driver manager holds the class of the driver for later use 703 ::std::auto_ptr< java_lang_Class > pDrvClass; 704 if ( !_sDriverClassPath.getLength() ) 705 { 706 // if forName didn't find the class it will throw an exception 707 pDrvClass = ::std::auto_ptr< java_lang_Class >(java_lang_Class::forName(_sDriverClass)); 708 } 709 else 710 { 711 LocalRef< jclass > driverClass(t.env()); 712 LocalRef< jobject > driverClassLoader(t.env()); 713 714 loadClass( 715 m_pDriver->getContext().getUNOContext(), 716 t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass ); 717 718 m_pDriverClassLoader.set( driverClassLoader ); 719 pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) ); 720 721 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); 722 } 723 if ( pDrvClass.get() ) 724 { 725 LocalRef< jobject > driverObject( t.env() ); 726 driverObject.set( pDrvClass->newInstanceObject() ); 727 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); 728 m_pDriverobject = driverObject.release(); 729 730 if( t.pEnv && m_pDriverobject ) 731 m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject ); 732 733 { 734 jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject); 735 if ( m_pDriverobject ) 736 { 737 m_Driver_theClass = (jclass)t.pEnv->NewGlobalRef( tempClass ); 738 t.pEnv->DeleteLocalRef( tempClass ); 739 } 740 } 741 } 742 m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS ); 743 } 744 } 745 } 746 catch( const SQLException& e ) 747 { 748 throw SQLException( 749 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), 750 *this, 751 ::rtl::OUString(), 752 1000, 753 makeAny(e) 754 ); 755 } 756 catch( Exception& ) 757 { 758 ::dbtools::throwGenericSQLException( 759 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), 760 *this 761 ); 762 } 763 764 enableAutoRetrievingEnabled( bAutoRetrievingEnabled ); 765 setAutoRetrievingStatement( sGeneratedValueStatement ); 766 } 767 // ----------------------------------------------------------------------------- 768 ::rtl::OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const ::rtl::OUString& _sDriverClass) 769 { 770 static const ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths")); 771 ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory( 772 m_pDriver->getContext().getLegacyServiceFactory(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY); 773 ::rtl::OUString sURL; 774 if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) ) 775 { 776 ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass ); 777 OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL ); 778 } 779 return sURL; 780 } 781 // ----------------------------------------------------------------------------- 782 sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url, 783 const Sequence< PropertyValue >& info) 784 { 785 { // initialize the java vm 786 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(getORB()); 787 if ( !xTest.is() ) 788 throwGenericSQLException(STR_NO_JAVA,*this); 789 } 790 SDBThreadAttach t; 791 t.addRef(); // will be released in dtor 792 if ( !t.pEnv ) 793 throwGenericSQLException(STR_NO_JAVA,*this); 794 795 ::rtl::OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values 796 sal_Bool bAutoRetrievingEnabled = sal_False; // set to <TRUE/> when we should allow to query for generated values 797 ::rtl::OUString sDriverClassPath,sDriverClass; 798 Sequence< NamedValue > aSystemProperties; 799 800 ::comphelper::NamedValueCollection aSettings( info ); 801 sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass ); 802 sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath); 803 if ( !sDriverClassPath.getLength() ) 804 sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass); 805 bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled ); 806 sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement ); 807 m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution ); 808 m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges ); 809 m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency ); 810 aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties ); 811 m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() ); 812 m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() ); 813 814 loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties ); 815 816 enableAutoRetrievingEnabled(bAutoRetrievingEnabled); 817 setAutoRetrievingStatement(sGeneratedValueStatement); 818 819 if ( t.pEnv && m_Driver_theClass && m_pDriverobject ) 820 { 821 // temporaere Variable initialisieren 822 static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;"; 823 static const char * cMethodName = "connect"; 824 // Java-Call absetzen 825 jmethodID mID = NULL; 826 if ( !mID ) 827 mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature ); 828 if ( mID ) 829 { 830 jvalue args[2]; 831 // Parameter konvertieren 832 args[0].l = convertwchar_tToJavaString(t.pEnv,url); 833 java_util_Properties* pProps = createStringPropertyArray(info); 834 args[1].l = pProps->getJavaObject(); 835 836 LocalRef< jobject > ensureDelete( t.env(), args[0].l ); 837 838 jobject out = NULL; 839 // In some cases (e.g., 840 // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24 841 // l. 249) the JavaDriverClassPath contains multiple jars, 842 // as creating the JavaDriverClass instance requires 843 // (reflective) access to those other jars. Now, if the 844 // JavaDriverClass is actually loaded by some parent class 845 // loader (e.g., because its jar is also on the global 846 // class path), it would still not have access to the 847 // additional jars on the JavaDriverClassPath. Hence, the 848 // JavaDriverClassPath class loader is pushed as context 849 // class loader around the JavaDriverClass instance 850 // creation: 851 // #i82222# / 2007-10-15 852 { 853 ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this ); 854 out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l ); 855 delete pProps, pProps = NULL; 856 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); 857 } 858 859 if ( !out ) 860 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION ); 861 862 if ( out ) 863 object = t.pEnv->NewGlobalRef( out ); 864 865 if ( object ) 866 m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url ); 867 868 m_aConnectionInfo = info; 869 } //mID 870 } //t.pEnv 871 return object != NULL; 872 } 873 // ----------------------------------------------------------------------------- 874