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