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