Bump for 3.6-28
[LibreOffice.git] / connectivity / source / drivers / jdbc / JConnection.cxx
blob7f107cbb654268fbd6ed92685a443ad852095631
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include "java/sql/Connection.hxx"
31 #include "java/lang/Class.hxx"
32 #include "java/tools.hxx"
33 #include "java/ContextClassLoader.hxx"
34 #include "java/sql/DatabaseMetaData.hxx"
35 #include "java/sql/JStatement.hxx"
36 #include "java/sql/Driver.hxx"
37 #include "java/sql/PreparedStatement.hxx"
38 #include "java/sql/CallableStatement.hxx"
39 #include "java/sql/SQLWarning.hxx"
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include <com/sun/star/sdbc/SQLWarning.hpp>
42 #include <com/sun/star/beans/NamedValue.hpp>
43 #include "connectivity/sqlparse.hxx"
44 #include "connectivity/dbexception.hxx"
45 #include "java/util/Property.hxx"
46 #include "java/LocalRef.hxx"
47 #include "resource/jdbc_log.hrc"
48 #include "com/sun/star/uno/XComponentContext.hpp"
49 #include "jvmaccess/classpath.hxx"
50 #include <comphelper/namedvaluecollection.hxx>
51 #include <rtl/ustrbuf.hxx>
52 #include <jni.h>
53 #include "resource/common_res.hrc"
54 #include <unotools/confignode.hxx>
56 #include <list>
57 #include <memory>
59 using namespace connectivity;
60 using namespace connectivity::jdbc;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::sdbc;
64 using namespace ::com::sun::star::container;
65 using namespace ::com::sun::star::lang;
67 namespace {
69 struct ClassMapEntry {
70 ClassMapEntry(
71 rtl::OUString const & theClassPath, rtl::OUString const & theClassName):
72 classPath(theClassPath), className(theClassName), classLoader(NULL),
73 classObject(NULL) {}
75 rtl::OUString classPath;
76 rtl::OUString className;
77 jweak classLoader;
78 jweak classObject;
81 typedef std::list< ClassMapEntry > ClassMap;
83 struct ClassMapData {
84 osl::Mutex mutex;
86 ClassMap map;
89 struct ClassMapDataInit {
90 ClassMapData * operator()() {
91 static ClassMapData instance;
92 return &instance;
96 template < typename T >
97 bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
99 _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) );
101 if ( !_inout_local.is() )
103 if ( _inout_local.env().ExceptionCheck())
105 return false;
107 else if ( _weak != NULL )
109 _inout_local.env().DeleteWeakGlobalRef( _weak );
110 _weak = NULL;
113 return true;
116 // Load a class. A map from pairs of (classPath, name) to pairs of weak Java
117 // references to (ClassLoader, Class) is maintained, so that a class is only
118 // loaded once.
120 // It may happen that the weak reference to the ClassLoader becomes null while
121 // the reference to the Class remains non-null (in case the Class was actually
122 // loaded by some parent of the ClassLoader), in which case the ClassLoader is
123 // resurrected (which cannot cause any classes to be loaded multiple times, as
124 // the ClassLoader is no longer reachable, so no classes it has ever loaded are
125 // still reachable).
127 // Similarly, it may happen that the weak reference to the Class becomes null
128 // while the reference to the ClassLoader remains non-null, in which case the
129 // Class is simply re-loaded.
131 // This code is close to the implementation of jvmaccess::ClassPath::loadClass
132 // in jvmaccess/classpath.hxx, but not close enough to avoid the duplication.
134 // If false is returned, a (still pending) JNI exception occurred.
135 bool loadClass(
136 Reference< XComponentContext > const & context, JNIEnv& environment,
137 rtl::OUString const & classPath, rtl::OUString const & name,
138 LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
140 OSL_ASSERT(classLoaderPtr != NULL);
141 // For any jweak entries still present in the map upon destruction,
142 // DeleteWeakGlobalRef is not called (which is a leak):
143 ClassMapData * d =
144 rtl_Instance< ClassMapData, ClassMapDataInit, osl::MutexGuard,
145 osl::GetGlobalMutex >::create(
146 ClassMapDataInit(), osl::GetGlobalMutex());
147 osl::MutexGuard g(d->mutex);
148 ClassMap::iterator i(d->map.begin());
149 LocalRef< jobject > cloader(environment);
150 LocalRef< jclass > cl(environment);
151 // Prune dangling weak references from the list while searching for a match,
152 // so that the list cannot grow unbounded:
153 for (; i != d->map.end();)
155 LocalRef< jobject > classLoader( environment );
156 if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
157 return false;
159 LocalRef< jclass > classObject( environment );
160 if ( !getLocalFromWeakRef( i->classObject, classObject ) )
161 return false;
163 if ( !classLoader.is() && !classObject.is() )
165 i = d->map.erase(i);
167 else if ( i->classPath == classPath && i->className == name )
169 cloader.set( classLoader.release() );
170 cl.set( classObject.release() );
171 break;
173 else
175 ++i;
178 if ( !cloader.is() || !cl.is() )
180 if ( i == d->map.end() )
182 // Push a new ClassMapEntry (which can potentially fail) before
183 // loading the class, so that it never happens that a class is
184 // loaded but not added to the map (which could have effects on the
185 // JVM that are not easily undone). If the pushed ClassMapEntry is
186 // not used after all (return false, etc.) it will be pruned on next
187 // call because its classLoader/classObject are null:
188 d->map.push_front( ClassMapEntry( classPath, name ) );
189 i = d->map.begin();
192 LocalRef< jclass > clClass( environment );
193 clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
194 if ( !clClass.is() )
195 return false;
197 jweak wcloader = NULL;
198 if (!cloader.is())
200 jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) );
201 if (ctorLoader == NULL)
202 return false;
204 LocalRef< jobjectArray > arr( environment );
205 arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) );
206 if ( !arr.is() )
207 return false;
209 jvalue arg;
210 arg.l = arr.get();
211 cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) );
212 if ( !cloader.is() )
213 return false;
215 wcloader = environment.NewWeakGlobalRef( cloader.get() );
216 if ( wcloader == NULL )
217 return false;
220 jweak wcl = NULL;
221 if ( !cl.is() )
223 jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
224 if ( methLoadClass == NULL )
225 return false;
227 LocalRef< jstring > str( environment );
228 str.set( convertwchar_tToJavaString( &environment, name ) );
229 if ( !str.is() )
230 return false;
232 jvalue arg;
233 arg.l = str.get();
234 cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) );
235 if ( !cl.is() )
236 return false;
238 wcl = environment.NewWeakGlobalRef( cl.get() );
239 if ( wcl == NULL )
240 return false;
243 if ( wcloader != NULL)
245 i->classLoader = wcloader;
247 if ( wcl != NULL )
249 i->classObject = wcl;
253 classLoaderPtr->set( cloader.release() );
254 classPtr->set( cl.release() );
255 return true;
260 //------------------------------------------------------------------------------
261 IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection");
262 //------------------------------------------------------------------------------
263 //**************************************************************
264 //************ Class: java.sql.Connection
265 //**************************************************************
266 jclass java_sql_Connection::theClass = 0;
268 java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver )
269 :java_lang_Object( _rDriver.getContext().getLegacyServiceFactory() )
270 ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this)
271 ,m_pDriver( &_rDriver )
272 ,m_pDriverobject(NULL)
273 ,m_pDriverClassLoader()
274 ,m_Driver_theClass(NULL)
275 ,m_aLogger( _rDriver.getLogger() )
276 ,m_bParameterSubstitution(sal_False)
277 ,m_bIgnoreDriverPrivileges(sal_True)
278 ,m_bIgnoreCurrency(sal_False)
281 // -----------------------------------------------------------------------------
282 java_sql_Connection::~java_sql_Connection()
284 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
285 if ( xTest.is() )
287 SDBThreadAttach t;
288 clearObject(*t.pEnv);
291 if ( m_pDriverobject )
292 t.pEnv->DeleteGlobalRef( m_pDriverobject );
293 m_pDriverobject = NULL;
294 if ( m_Driver_theClass )
295 t.pEnv->DeleteGlobalRef( m_Driver_theClass );
296 m_Driver_theClass = NULL;
298 t.releaseRef();
301 //-----------------------------------------------------------------------------
302 void SAL_CALL java_sql_Connection::release() throw()
304 relase_ChildImpl();
306 //------------------------------------------------------------------------------
307 void java_sql_Connection::disposing()
309 ::osl::MutexGuard aGuard(m_aMutex);
311 m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
313 dispose_ChildImpl();
314 java_sql_Connection_BASE::disposing();
316 if ( object )
318 static jmethodID mID(NULL);
319 callVoidMethod("close",mID);
322 // -------------------------------------------------------------------------
323 jclass java_sql_Connection::getMyClass() const
325 // the class must be fetched only once, therefore static
326 if( !theClass )
327 theClass = findMyClass("java/sql/Connection");
328 return theClass;
331 // -------------------------------------------------------------------------
332 ::rtl::OUString SAL_CALL java_sql_Connection::getCatalog( ) throw(SQLException, RuntimeException)
334 ::osl::MutexGuard aGuard( m_aMutex );
335 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
337 static jmethodID mID(NULL);
338 return callStringMethod("getCatalog",mID);
340 // -------------------------------------------------------------------------
341 Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException)
343 ::osl::MutexGuard aGuard( m_aMutex );
344 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
347 Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
348 if(!xMetaData.is())
350 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
351 static jmethodID mID(NULL);
352 jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
353 if(out)
355 xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
356 m_xMetaData = xMetaData;
360 return xMetaData;
362 // -------------------------------------------------------------------------
363 void SAL_CALL java_sql_Connection::close( ) throw(SQLException, RuntimeException)
365 dispose();
367 // -------------------------------------------------------------------------
368 void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException)
370 static jmethodID mID(NULL);
371 callVoidMethod("commit",mID);
373 // -------------------------------------------------------------------------
374 sal_Bool SAL_CALL java_sql_Connection::isClosed( ) throw(SQLException, RuntimeException)
376 ::osl::MutexGuard aGuard( m_aMutex );
378 static jmethodID mID(NULL);
379 return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
381 // -------------------------------------------------------------------------
382 sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) throw(SQLException, RuntimeException)
384 ::osl::MutexGuard aGuard( m_aMutex );
385 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
386 static jmethodID mID(NULL);
387 return callBooleanMethod( "isReadOnly", mID );
389 // -------------------------------------------------------------------------
390 void SAL_CALL java_sql_Connection::setCatalog( const ::rtl::OUString& catalog ) throw(SQLException, RuntimeException)
392 static jmethodID mID(NULL);
393 callVoidMethodWithStringArg("setCatalog",mID,catalog);
395 // -------------------------------------------------------------------------
396 void SAL_CALL java_sql_Connection::rollback( ) throw(SQLException, RuntimeException)
398 static jmethodID mID(NULL);
399 callVoidMethod("rollback",mID);
401 // -------------------------------------------------------------------------
402 sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException)
404 static jmethodID mID(NULL);
405 return callBooleanMethod( "getAutoCommit", mID );
407 // -------------------------------------------------------------------------
408 void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException)
410 static jmethodID mID(NULL);
411 callVoidMethodWithBoolArg("setReadOnly",mID,readOnly);
413 // -------------------------------------------------------------------------
414 void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException)
416 static jmethodID mID(NULL);
417 callVoidMethodWithBoolArg("setAutoCommit",mID,autoCommit);
419 // -------------------------------------------------------------------------
420 Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) throw(SQLException, RuntimeException)
422 ::osl::MutexGuard aGuard( m_aMutex );
423 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
425 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
426 static jmethodID mID(NULL);
427 callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
428 // WARNING: the caller becomes the owner of the returned pointer
429 return 0;
431 // -------------------------------------------------------------------------
432 void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException)
434 ::osl::MutexGuard aGuard( m_aMutex );
435 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
437 ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
440 // -------------------------------------------------------------------------
441 sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException)
443 ::osl::MutexGuard aGuard( m_aMutex );
444 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
446 static jmethodID mID(NULL);
447 return callIntMethod("getTransactionIsolation",mID);
449 // -------------------------------------------------------------------------
450 void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException)
452 ::osl::MutexGuard aGuard( m_aMutex );
453 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
455 static jmethodID mID(NULL);
456 callVoidMethodWithIntArg("setTransactionIsolation",mID,level);
458 // -------------------------------------------------------------------------
459 Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException)
461 ::osl::MutexGuard aGuard( m_aMutex );
462 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
463 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
465 SDBThreadAttach t;
466 java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this );
467 Reference< XStatement > xStmt = pStatement;
468 m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
470 m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
471 return xStmt;
473 // -----------------------------------------------------------------------------
474 ::rtl::OUString java_sql_Connection::transFormPreparedStatement(const ::rtl::OUString& _sSQL)
476 ::rtl::OUString sSqlStatement = _sSQL;
477 if ( m_bParameterSubstitution )
481 OSQLParser aParser( m_pDriver->getContext().getLegacyServiceFactory() );
482 ::rtl::OUString sErrorMessage;
483 ::rtl::OUString sNewSql;
484 OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
485 if(pNode)
486 { // special handling for parameters
487 OSQLParseNode::substituteParameterNames(pNode);
488 pNode->parseNodeToStr( sNewSql, this );
489 delete pNode;
490 sSqlStatement = sNewSql;
493 catch(const Exception&)
497 return sSqlStatement;
499 // -------------------------------------------------------------------------
500 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
502 ::osl::MutexGuard aGuard( m_aMutex );
503 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
504 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
506 SDBThreadAttach t;
507 ::rtl::OUString sSqlStatement = sql;
508 sSqlStatement = transFormPreparedStatement( sSqlStatement );
510 java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement );
511 Reference< XPreparedStatement > xReturn( pStatement );
512 m_aStatements.push_back(WeakReferenceHelper(xReturn));
514 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
515 return xReturn;
517 // -------------------------------------------------------------------------
518 Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
520 ::osl::MutexGuard aGuard( m_aMutex );
521 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
522 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
524 SDBThreadAttach t;
525 ::rtl::OUString sSqlStatement = sql;
526 sSqlStatement = transFormPreparedStatement( sSqlStatement );
528 java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement );
529 Reference< XPreparedStatement > xStmt( pStatement );
530 m_aStatements.push_back(WeakReferenceHelper(xStmt));
532 m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
533 return xStmt;
535 // -------------------------------------------------------------------------
536 ::rtl::OUString SAL_CALL java_sql_Connection::nativeSQL( const ::rtl::OUString& sql ) throw(SQLException, RuntimeException)
538 ::osl::MutexGuard aGuard( m_aMutex );
539 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
541 ::rtl::OUString aStr;
542 SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
545 // initialize temporary Variable
546 static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
547 static const char * cMethodName = "nativeSQL";
548 // Java-Call
549 static jmethodID mID(NULL);
550 obtainMethodId(t.pEnv, cMethodName,cSignature, mID);
551 // Convert Parameter
552 jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
554 jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
555 aStr = JavaString2String(t.pEnv, (jstring)out );
556 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
557 } //t.pEnv
559 m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
561 return aStr;
563 // -------------------------------------------------------------------------
564 void SAL_CALL java_sql_Connection::clearWarnings( ) throw(SQLException, RuntimeException)
566 static jmethodID mID(NULL);
567 callVoidMethod("clearWarnings",mID);
569 // -------------------------------------------------------------------------
570 Any SAL_CALL java_sql_Connection::getWarnings( ) throw(SQLException, RuntimeException)
572 ::osl::MutexGuard aGuard( m_aMutex );
573 checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
575 SDBThreadAttach t;
576 static jmethodID mID(NULL);
577 jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
578 // WARNING: the caller becomes the owner of the returned pointer
579 if( out )
581 java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
582 SQLException aAsException( static_cast< starsdbc::SQLException >( java_sql_SQLWarning( warn_base, *this ) ) );
584 // translate to warning
585 SQLWarning aWarning;
586 aWarning.Context = aAsException.Context;
587 aWarning.Message = aAsException.Message;
588 aWarning.SQLState = aAsException.SQLState;
589 aWarning.ErrorCode = aAsException.ErrorCode;
590 aWarning.NextException = aAsException.NextException;
592 return makeAny( aWarning );
595 return Any();
598 // -----------------------------------------------------------------------------
599 namespace
601 ::rtl::OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const ::rtl::OUString& _rDriverClass, const ::rtl::OUString& _rDriverClassPath )
603 ::rtl::OUString sError1( _aResource.getResourceStringWithSubstitution(
604 STR_NO_CLASSNAME,
605 "$classname$", _rDriverClass
606 ) );
607 if ( !_rDriverClassPath.isEmpty() )
609 const ::rtl::OUString sError2( _aResource.getResourceStringWithSubstitution(
610 STR_NO_CLASSNAME_PATH,
611 "$classpath$", _rDriverClassPath
612 ) );
613 sError1 += sError2;
614 } // if ( _rDriverClassPath.getLength() )
615 return sError1;
619 // -----------------------------------------------------------------------------
620 namespace
622 bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
623 JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
625 if ( _rSystemProperties.getLength() == 0 )
626 // nothing to do
627 return true;
629 LocalRef< jclass > systemClass( _rEnv );
630 jmethodID nSetPropertyMethodID = 0;
631 // retrieve the java.lang.System class
632 systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
633 if ( systemClass.is() )
635 nSetPropertyMethodID = _rEnv.GetStaticMethodID(
636 systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
639 if ( nSetPropertyMethodID == 0 )
640 return false;
642 for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray();
643 pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength();
644 ++pSystemProp
647 ::rtl::OUString sValue;
648 OSL_VERIFY( pSystemProp->Value >>= sValue );
650 _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue );
652 LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) );
653 LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
655 _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
656 LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
657 if ( throwable.is() )
658 return false;
661 return true;
665 // -----------------------------------------------------------------------------
666 void java_sql_Connection::loadDriverFromProperties( const ::rtl::OUString& _sDriverClass, const ::rtl::OUString& _sDriverClassPath,
667 const Sequence< NamedValue >& _rSystemProperties )
669 // contains the statement which should be used when query for automatically generated values
670 ::rtl::OUString sGeneratedValueStatement;
671 // set to <TRUE/> when we should allow to query for generated values
672 sal_Bool bAutoRetrievingEnabled = sal_False;
674 // first try if the jdbc driver is alraedy registered at the driver manager
675 SDBThreadAttach t;
678 if ( !object )
680 if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
681 ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
683 m_pDriverClassLoader.reset();
685 // here I try to find the class for jdbc driver
686 java_sql_SQLException_BASE::st_getMyClass();
687 java_lang_Throwable::st_getMyClass();
689 if ( _sDriverClass.isEmpty() )
691 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
692 ::dbtools::throwGenericSQLException(
693 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
694 *this
697 else
699 m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
700 // the driver manager holds the class of the driver for later use
701 ::std::auto_ptr< java_lang_Class > pDrvClass;
702 if ( _sDriverClassPath.isEmpty() )
704 // if forName didn't find the class it will throw an exception
705 pDrvClass = ::std::auto_ptr< java_lang_Class >(java_lang_Class::forName(_sDriverClass));
707 else
709 LocalRef< jclass > driverClass(t.env());
710 LocalRef< jobject > driverClassLoader(t.env());
712 loadClass(
713 m_pDriver->getContext().getUNOContext(),
714 t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
716 m_pDriverClassLoader.set( driverClassLoader );
717 pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
719 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
721 if ( pDrvClass.get() )
723 LocalRef< jobject > driverObject( t.env() );
724 driverObject.set( pDrvClass->newInstanceObject() );
725 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
726 m_pDriverobject = driverObject.release();
728 if( t.pEnv && m_pDriverobject )
729 m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
732 jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
733 if ( m_pDriverobject )
735 m_Driver_theClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
736 t.pEnv->DeleteLocalRef( tempClass );
740 m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
744 catch( const SQLException& e )
746 throw SQLException(
747 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
748 *this,
749 ::rtl::OUString(),
750 1000,
751 makeAny(e)
754 catch( Exception& )
756 ::dbtools::throwGenericSQLException(
757 lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
758 *this
762 enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
763 setAutoRetrievingStatement( sGeneratedValueStatement );
765 // -----------------------------------------------------------------------------
766 ::rtl::OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const ::rtl::OUString& _sDriverClass)
768 static const ::rtl::OUString s_sNodeName(RTL_CONSTASCII_USTRINGPARAM("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths"));
769 ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithServiceFactory(
770 m_pDriver->getContext().getLegacyServiceFactory(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
771 ::rtl::OUString sURL;
772 if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
774 ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
775 OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
777 return sURL;
779 // -----------------------------------------------------------------------------
780 sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url,
781 const Sequence< PropertyValue >& info)
783 { // initialize the java vm
784 ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(getORB());
785 if ( !xTest.is() )
786 throwGenericSQLException(STR_NO_JAVA,*this);
788 SDBThreadAttach t;
789 t.addRef(); // will be released in dtor
790 if ( !t.pEnv )
791 throwGenericSQLException(STR_NO_JAVA,*this);
793 ::rtl::OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
794 sal_Bool bAutoRetrievingEnabled = sal_False; // set to <TRUE/> when we should allow to query for generated values
795 ::rtl::OUString sDriverClassPath,sDriverClass;
796 Sequence< NamedValue > aSystemProperties;
798 ::comphelper::NamedValueCollection aSettings( info );
799 sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
800 sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
801 if ( sDriverClassPath.isEmpty() )
802 sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
803 bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
804 sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
805 m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
806 m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
807 m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
808 aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
809 m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
810 m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
812 loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
814 enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
815 setAutoRetrievingStatement(sGeneratedValueStatement);
817 if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
819 // initialize temporary Variable
820 static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
821 static const char * cMethodName = "connect";
822 // Java-Call
823 jmethodID mID = NULL;
824 if ( !mID )
825 mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
826 if ( mID )
828 jvalue args[2];
829 // convert Parameter
830 args[0].l = convertwchar_tToJavaString(t.pEnv,url);
831 java_util_Properties* pProps = createStringPropertyArray(info);
832 args[1].l = pProps->getJavaObject();
834 LocalRef< jobject > ensureDelete( t.env(), args[0].l );
836 jobject out = NULL;
837 // In some cases (e.g.,
838 // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
839 // l. 249) the JavaDriverClassPath contains multiple jars,
840 // as creating the JavaDriverClass instance requires
841 // (reflective) access to those other jars. Now, if the
842 // JavaDriverClass is actually loaded by some parent class
843 // loader (e.g., because its jar is also on the global
844 // class path), it would still not have access to the
845 // additional jars on the JavaDriverClassPath. Hence, the
846 // JavaDriverClassPath class loader is pushed as context
847 // class loader around the JavaDriverClass instance
848 // creation:
849 // #i82222# / 2007-10-15
851 ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
852 out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
853 delete pProps, pProps = NULL;
854 ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
857 if ( !out )
858 m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
860 if ( out )
861 object = t.pEnv->NewGlobalRef( out );
863 if ( object )
864 m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
866 m_aConnectionInfo = info;
867 } //mID
868 } //t.pEnv
869 return object != NULL;
871 // -----------------------------------------------------------------------------
873 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */