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