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 : OUString const & theClassPath, OUString const & theClassName):
63 : classPath(theClassPath), className(theClassName), classLoader(NULL),
64 0 : classObject(NULL) {}
65 :
66 : OUString classPath;
67 : 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 : OUString const & classPath, 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 0 : 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 : :java_lang_Object()
261 : ,OSubComponent<java_sql_Connection, java_sql_Connection_BASE>((::cppu::OWeakObject*)(&_rDriver), this)
262 0 : ,m_xContext( _rDriver.getContext() )
263 : ,m_pDriver( &_rDriver )
264 : ,m_pDriverobject(NULL)
265 : ,m_pDriverClassLoader()
266 : ,m_Driver_theClass(NULL)
267 0 : ,m_aLogger( _rDriver.getLogger() )
268 : ,m_bParameterSubstitution(sal_False)
269 : ,m_bIgnoreDriverPrivileges(sal_True)
270 0 : ,m_bIgnoreCurrency(sal_False)
271 : {
272 0 : }
273 : // -----------------------------------------------------------------------------
274 0 : java_sql_Connection::~java_sql_Connection()
275 : {
276 0 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM();
277 0 : if ( xTest.is() )
278 : {
279 0 : SDBThreadAttach t;
280 0 : clearObject(*t.pEnv);
281 :
282 : {
283 0 : if ( m_pDriverobject )
284 0 : t.pEnv->DeleteGlobalRef( m_pDriverobject );
285 0 : m_pDriverobject = NULL;
286 0 : if ( m_Driver_theClass )
287 0 : t.pEnv->DeleteGlobalRef( m_Driver_theClass );
288 0 : m_Driver_theClass = NULL;
289 : }
290 0 : t.releaseRef();
291 0 : }
292 0 : }
293 : //-----------------------------------------------------------------------------
294 0 : void SAL_CALL java_sql_Connection::release() throw()
295 : {
296 0 : relase_ChildImpl();
297 0 : }
298 : //------------------------------------------------------------------------------
299 0 : void java_sql_Connection::disposing()
300 : {
301 0 : ::osl::MutexGuard aGuard(m_aMutex);
302 :
303 0 : m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION );
304 :
305 0 : dispose_ChildImpl();
306 0 : java_sql_Connection_BASE::disposing();
307 :
308 0 : if ( object )
309 : {
310 : static jmethodID mID(NULL);
311 0 : callVoidMethod("close",mID);
312 0 : }
313 0 : }
314 : // -------------------------------------------------------------------------
315 0 : jclass java_sql_Connection::getMyClass() const
316 : {
317 : // the class must be fetched only once, therefore static
318 0 : if( !theClass )
319 0 : theClass = findMyClass("java/sql/Connection");
320 0 : return theClass;
321 : }
322 :
323 : // -------------------------------------------------------------------------
324 0 : OUString SAL_CALL java_sql_Connection::getCatalog( ) throw(SQLException, RuntimeException)
325 : {
326 0 : ::osl::MutexGuard aGuard( m_aMutex );
327 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
328 :
329 : static jmethodID mID(NULL);
330 0 : return callStringMethod("getCatalog",mID);
331 : }
332 : // -------------------------------------------------------------------------
333 0 : Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) throw(SQLException, RuntimeException)
334 : {
335 0 : ::osl::MutexGuard aGuard( m_aMutex );
336 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
337 :
338 :
339 0 : Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
340 0 : if(!xMetaData.is())
341 : {
342 0 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
343 : static jmethodID mID(NULL);
344 0 : jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID);
345 0 : if(out)
346 : {
347 0 : xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this );
348 0 : m_xMetaData = xMetaData;
349 0 : }
350 : }
351 :
352 0 : return xMetaData;
353 : }
354 : // -------------------------------------------------------------------------
355 0 : void SAL_CALL java_sql_Connection::close( ) throw(SQLException, RuntimeException)
356 : {
357 0 : dispose();
358 0 : }
359 : // -------------------------------------------------------------------------
360 0 : void SAL_CALL java_sql_Connection::commit( ) throw(SQLException, RuntimeException)
361 : {
362 : static jmethodID mID(NULL);
363 0 : callVoidMethod("commit",mID);
364 0 : }
365 : // -------------------------------------------------------------------------
366 0 : sal_Bool SAL_CALL java_sql_Connection::isClosed( ) throw(SQLException, RuntimeException)
367 : {
368 0 : ::osl::MutexGuard aGuard( m_aMutex );
369 :
370 : static jmethodID mID(NULL);
371 0 : return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed;
372 : }
373 : // -------------------------------------------------------------------------
374 0 : sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) throw(SQLException, RuntimeException)
375 : {
376 0 : ::osl::MutexGuard aGuard( m_aMutex );
377 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
378 : static jmethodID mID(NULL);
379 0 : return callBooleanMethod( "isReadOnly", mID );
380 : }
381 : // -------------------------------------------------------------------------
382 0 : void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog ) throw(SQLException, RuntimeException)
383 : {
384 : static jmethodID mID(NULL);
385 0 : callVoidMethodWithStringArg("setCatalog",mID,catalog);
386 0 : }
387 : // -------------------------------------------------------------------------
388 0 : void SAL_CALL java_sql_Connection::rollback( ) throw(SQLException, RuntimeException)
389 : {
390 : static jmethodID mID(NULL);
391 0 : callVoidMethod("rollback",mID);
392 0 : }
393 : // -------------------------------------------------------------------------
394 0 : sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) throw(SQLException, RuntimeException)
395 : {
396 : static jmethodID mID(NULL);
397 0 : return callBooleanMethod( "getAutoCommit", mID );
398 : }
399 : // -------------------------------------------------------------------------
400 0 : void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) throw(SQLException, RuntimeException)
401 : {
402 : static jmethodID mID(NULL);
403 0 : callVoidMethodWithBoolArg("setReadOnly",mID,readOnly);
404 0 : }
405 : // -------------------------------------------------------------------------
406 0 : void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) throw(SQLException, RuntimeException)
407 : {
408 : static jmethodID mID(NULL);
409 0 : callVoidMethodWithBoolArg("setAutoCommit",mID,autoCommit);
410 0 : }
411 : // -------------------------------------------------------------------------
412 0 : Reference< ::com::sun::star::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) throw(SQLException, RuntimeException)
413 : {
414 0 : ::osl::MutexGuard aGuard( m_aMutex );
415 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
416 :
417 0 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
418 : static jmethodID mID(NULL);
419 0 : callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID);
420 : // WARNING: the caller becomes the owner of the returned pointer
421 0 : return 0;
422 : }
423 : // -------------------------------------------------------------------------
424 0 : void SAL_CALL java_sql_Connection::setTypeMap( const Reference< ::com::sun::star::container::XNameAccess >& /*typeMap*/ ) throw(SQLException, RuntimeException)
425 : {
426 0 : ::osl::MutexGuard aGuard( m_aMutex );
427 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
428 :
429 0 : ::dbtools::throwFeatureNotImplementedException( "XConnection::setTypeMap", *this );
430 0 : }
431 :
432 : // -------------------------------------------------------------------------
433 0 : sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) throw(SQLException, RuntimeException)
434 : {
435 0 : ::osl::MutexGuard aGuard( m_aMutex );
436 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
437 :
438 : static jmethodID mID(NULL);
439 0 : return callIntMethod("getTransactionIsolation",mID);
440 : }
441 : // -------------------------------------------------------------------------
442 0 : void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) throw(SQLException, RuntimeException)
443 : {
444 0 : ::osl::MutexGuard aGuard( m_aMutex );
445 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
446 :
447 : static jmethodID mID(NULL);
448 0 : callVoidMethodWithIntArg("setTransactionIsolation",mID,level);
449 0 : }
450 : // -------------------------------------------------------------------------
451 0 : Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) throw(SQLException, RuntimeException)
452 : {
453 0 : ::osl::MutexGuard aGuard( m_aMutex );
454 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
455 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT );
456 :
457 0 : SDBThreadAttach t;
458 0 : java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this );
459 0 : Reference< XStatement > xStmt = pStatement;
460 0 : m_aStatements.push_back( WeakReferenceHelper( xStmt ) );
461 :
462 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() );
463 0 : return xStmt;
464 : }
465 : // -----------------------------------------------------------------------------
466 0 : OUString java_sql_Connection::transFormPreparedStatement(const OUString& _sSQL)
467 : {
468 0 : OUString sSqlStatement = _sSQL;
469 0 : if ( m_bParameterSubstitution )
470 : {
471 : try
472 : {
473 0 : OSQLParser aParser( m_pDriver->getContext() );
474 0 : OUString sErrorMessage;
475 0 : OUString sNewSql;
476 0 : OSQLParseNode* pNode = aParser.parseTree(sErrorMessage,_sSQL);
477 0 : if(pNode)
478 : { // special handling for parameters
479 0 : OSQLParseNode::substituteParameterNames(pNode);
480 0 : pNode->parseNodeToStr( sNewSql, this );
481 0 : delete pNode;
482 0 : sSqlStatement = sNewSql;
483 0 : }
484 : }
485 0 : catch(const Exception&)
486 : {
487 : }
488 : }
489 0 : return sSqlStatement;
490 : }
491 : // -------------------------------------------------------------------------
492 0 : Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql ) throw(SQLException, RuntimeException)
493 : {
494 0 : ::osl::MutexGuard aGuard( m_aMutex );
495 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
496 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql );
497 :
498 0 : SDBThreadAttach t;
499 0 : OUString sSqlStatement = sql;
500 0 : sSqlStatement = transFormPreparedStatement( sSqlStatement );
501 :
502 0 : java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sSqlStatement );
503 0 : Reference< XPreparedStatement > xReturn( pStatement );
504 0 : m_aStatements.push_back(WeakReferenceHelper(xReturn));
505 :
506 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() );
507 0 : return xReturn;
508 : }
509 : // -------------------------------------------------------------------------
510 0 : Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql ) throw(SQLException, RuntimeException)
511 : {
512 0 : ::osl::MutexGuard aGuard( m_aMutex );
513 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
514 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql );
515 :
516 0 : SDBThreadAttach t;
517 0 : OUString sSqlStatement = sql;
518 0 : sSqlStatement = transFormPreparedStatement( sSqlStatement );
519 :
520 0 : java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sSqlStatement );
521 0 : Reference< XPreparedStatement > xStmt( pStatement );
522 0 : m_aStatements.push_back(WeakReferenceHelper(xStmt));
523 :
524 0 : m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() );
525 0 : return xStmt;
526 : }
527 : // -------------------------------------------------------------------------
528 0 : OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql ) throw(SQLException, RuntimeException)
529 : {
530 0 : ::osl::MutexGuard aGuard( m_aMutex );
531 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
532 :
533 0 : OUString aStr;
534 0 : SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
535 : {
536 :
537 : // initialize temporary Variable
538 : static const char * cSignature = "(Ljava/lang/String;)Ljava/lang/String;";
539 : static const char * cMethodName = "nativeSQL";
540 : // Java-Call
541 : static jmethodID mID(NULL);
542 0 : obtainMethodId(t.pEnv, cMethodName,cSignature, mID);
543 : // Convert Parameter
544 0 : jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql));
545 :
546 0 : jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() );
547 0 : aStr = JavaString2String(t.pEnv, (jstring)out );
548 0 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
549 : } //t.pEnv
550 :
551 0 : m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr );
552 :
553 0 : return aStr;
554 : }
555 : // -------------------------------------------------------------------------
556 0 : void SAL_CALL java_sql_Connection::clearWarnings( ) throw(SQLException, RuntimeException)
557 : {
558 : static jmethodID mID(NULL);
559 0 : callVoidMethod("clearWarnings",mID);
560 0 : }
561 : // -------------------------------------------------------------------------
562 0 : Any SAL_CALL java_sql_Connection::getWarnings( ) throw(SQLException, RuntimeException)
563 : {
564 0 : ::osl::MutexGuard aGuard( m_aMutex );
565 0 : checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed);
566 :
567 0 : SDBThreadAttach t;
568 : static jmethodID mID(NULL);
569 0 : jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID);
570 : // WARNING: the caller becomes the owner of the returned pointer
571 0 : if( out )
572 : {
573 0 : java_sql_SQLWarning_BASE warn_base(t.pEnv, out);
574 0 : SQLException aAsException( static_cast< starsdbc::SQLException >( java_sql_SQLWarning( warn_base, *this ) ) );
575 :
576 : // translate to warning
577 0 : SQLWarning aWarning;
578 0 : aWarning.Context = aAsException.Context;
579 0 : aWarning.Message = aAsException.Message;
580 0 : aWarning.SQLState = aAsException.SQLState;
581 0 : aWarning.ErrorCode = aAsException.ErrorCode;
582 0 : aWarning.NextException = aAsException.NextException;
583 :
584 0 : return makeAny( aWarning );
585 : }
586 :
587 0 : return Any();
588 : }
589 :
590 : // -----------------------------------------------------------------------------
591 : namespace
592 : {
593 0 : OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath )
594 : {
595 : OUString sError1( _aResource.getResourceStringWithSubstitution(
596 : STR_NO_CLASSNAME,
597 : "$classname$", _rDriverClass
598 0 : ) );
599 0 : if ( !_rDriverClassPath.isEmpty() )
600 : {
601 : const OUString sError2( _aResource.getResourceStringWithSubstitution(
602 : STR_NO_CLASSNAME_PATH,
603 : "$classpath$", _rDriverClassPath
604 0 : ) );
605 0 : sError1 += sError2;
606 : } // if ( _rDriverClassPath.getLength() )
607 0 : return sError1;
608 : }
609 : }
610 :
611 : // -----------------------------------------------------------------------------
612 : namespace
613 : {
614 0 : bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger,
615 : JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties )
616 : {
617 0 : if ( _rSystemProperties.getLength() == 0 )
618 : // nothing to do
619 0 : return true;
620 :
621 0 : LocalRef< jclass > systemClass( _rEnv );
622 0 : jmethodID nSetPropertyMethodID = 0;
623 : // retrieve the java.lang.System class
624 0 : systemClass.set( _rEnv.FindClass( "java/lang/System" ) );
625 0 : if ( systemClass.is() )
626 : {
627 : nSetPropertyMethodID = _rEnv.GetStaticMethodID(
628 0 : systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" );
629 : }
630 :
631 0 : if ( nSetPropertyMethodID == 0 )
632 0 : return false;
633 :
634 0 : for ( const NamedValue* pSystemProp = _rSystemProperties.getConstArray();
635 0 : pSystemProp != _rSystemProperties.getConstArray() + _rSystemProperties.getLength();
636 : ++pSystemProp
637 : )
638 : {
639 0 : OUString sValue;
640 0 : OSL_VERIFY( pSystemProp->Value >>= sValue );
641 :
642 0 : _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, pSystemProp->Name, sValue );
643 :
644 0 : LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, pSystemProp->Name ) );
645 0 : LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) );
646 :
647 0 : _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() );
648 0 : LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() );
649 0 : if ( throwable.is() )
650 0 : return false;
651 0 : }
652 :
653 0 : return true;
654 : }
655 : }
656 :
657 : // -----------------------------------------------------------------------------
658 0 : void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath,
659 : const Sequence< NamedValue >& _rSystemProperties )
660 : {
661 : // contains the statement which should be used when query for automatically generated values
662 0 : OUString sGeneratedValueStatement;
663 : // set to <TRUE/> when we should allow to query for generated values
664 0 : sal_Bool bAutoRetrievingEnabled = sal_False;
665 :
666 : // first try if the jdbc driver is already registered at the driver manager
667 0 : SDBThreadAttach t;
668 : try
669 : {
670 0 : if ( !object )
671 : {
672 0 : if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) )
673 0 : ThrowLoggedSQLException( getLogger(), t.pEnv, *this );
674 :
675 0 : m_pDriverClassLoader.reset();
676 :
677 : // here I try to find the class for jdbc driver
678 0 : java_sql_SQLException_BASE::st_getMyClass();
679 0 : java_lang_Throwable::st_getMyClass();
680 :
681 0 : if ( _sDriverClass.isEmpty() )
682 : {
683 0 : m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS );
684 : ::dbtools::throwGenericSQLException(
685 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
686 : *this
687 0 : );
688 : }
689 : else
690 : {
691 0 : m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass );
692 : // the driver manager holds the class of the driver for later use
693 0 : ::std::auto_ptr< java_lang_Class > pDrvClass;
694 0 : if ( _sDriverClassPath.isEmpty() )
695 : {
696 : // if forName didn't find the class it will throw an exception
697 0 : pDrvClass = ::std::auto_ptr< java_lang_Class >(java_lang_Class::forName(_sDriverClass));
698 : }
699 : else
700 : {
701 0 : LocalRef< jclass > driverClass(t.env());
702 0 : LocalRef< jobject > driverClassLoader(t.env());
703 :
704 : loadClass(
705 0 : m_pDriver->getContext(),
706 0 : t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass );
707 :
708 0 : m_pDriverClassLoader.set( driverClassLoader );
709 0 : pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) );
710 :
711 0 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
712 : }
713 0 : if ( pDrvClass.get() )
714 : {
715 0 : LocalRef< jobject > driverObject( t.env() );
716 0 : driverObject.set( pDrvClass->newInstanceObject() );
717 0 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
718 0 : m_pDriverobject = driverObject.release();
719 :
720 0 : if( t.pEnv && m_pDriverobject )
721 0 : m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject );
722 :
723 : {
724 0 : jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject);
725 0 : if ( m_pDriverobject )
726 : {
727 0 : m_Driver_theClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
728 0 : t.pEnv->DeleteLocalRef( tempClass );
729 : }
730 0 : }
731 : }
732 0 : m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS );
733 : }
734 : }
735 : }
736 0 : catch( const SQLException& e )
737 : {
738 : throw SQLException(
739 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
740 : *this,
741 : OUString(),
742 : 1000,
743 : makeAny(e)
744 0 : );
745 : }
746 0 : catch( Exception& )
747 : {
748 : ::dbtools::throwGenericSQLException(
749 0 : lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ),
750 : *this
751 0 : );
752 : }
753 :
754 0 : enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
755 0 : setAutoRetrievingStatement( sGeneratedValueStatement );
756 0 : }
757 : // -----------------------------------------------------------------------------
758 0 : OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass)
759 : {
760 0 : static const OUString s_sNodeName("org.openoffice.Office.DataAccess/JDBC/DriverClassPaths");
761 : ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
762 0 : m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY);
763 0 : OUString sURL;
764 0 : if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) )
765 : {
766 0 : ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass );
767 0 : OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL );
768 : }
769 0 : return sURL;
770 : }
771 : // -----------------------------------------------------------------------------
772 0 : sal_Bool java_sql_Connection::construct(const OUString& url,
773 : const Sequence< PropertyValue >& info)
774 : {
775 : { // initialize the java vm
776 0 : ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext);
777 0 : if ( !xTest.is() )
778 0 : throwGenericSQLException(STR_NO_JAVA,*this);
779 : }
780 0 : SDBThreadAttach t;
781 0 : t.addRef(); // will be released in dtor
782 0 : if ( !t.pEnv )
783 0 : throwGenericSQLException(STR_NO_JAVA,*this);
784 :
785 0 : OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values
786 0 : sal_Bool bAutoRetrievingEnabled = sal_False; // set to <TRUE/> when we should allow to query for generated values
787 0 : OUString sDriverClassPath,sDriverClass;
788 0 : Sequence< NamedValue > aSystemProperties;
789 :
790 0 : ::comphelper::NamedValueCollection aSettings( info );
791 0 : sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass );
792 0 : sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath);
793 0 : if ( sDriverClassPath.isEmpty() )
794 0 : sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass);
795 0 : bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled );
796 0 : sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement );
797 0 : m_bParameterSubstitution = aSettings.getOrDefault( "ParameterNameSubstitution", m_bParameterSubstitution );
798 0 : m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges );
799 0 : m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency );
800 0 : aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties );
801 0 : m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() );
802 0 : m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() );
803 :
804 0 : loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties );
805 :
806 0 : enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
807 0 : setAutoRetrievingStatement(sGeneratedValueStatement);
808 :
809 0 : if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
810 : {
811 : // initialize temporary Variable
812 : static const char * cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;";
813 : static const char * cMethodName = "connect";
814 : // Java-Call
815 0 : jmethodID mID = NULL;
816 0 : if ( !mID )
817 0 : mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature );
818 0 : if ( mID )
819 : {
820 : jvalue args[2];
821 : // convert Parameter
822 0 : args[0].l = convertwchar_tToJavaString(t.pEnv,url);
823 0 : java_util_Properties* pProps = createStringPropertyArray(info);
824 0 : args[1].l = pProps->getJavaObject();
825 :
826 0 : LocalRef< jobject > ensureDelete( t.env(), args[0].l );
827 :
828 0 : jobject out = NULL;
829 : // In some cases (e.g.,
830 : // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
831 : // l. 249) the JavaDriverClassPath contains multiple jars,
832 : // as creating the JavaDriverClass instance requires
833 : // (reflective) access to those other jars. Now, if the
834 : // JavaDriverClass is actually loaded by some parent class
835 : // loader (e.g., because its jar is also on the global
836 : // class path), it would still not have access to the
837 : // additional jars on the JavaDriverClassPath. Hence, the
838 : // JavaDriverClassPath class loader is pushed as context
839 : // class loader around the JavaDriverClass instance
840 : // creation:
841 : // #i82222# / 2007-10-15
842 : {
843 0 : ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this );
844 0 : out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l );
845 0 : delete pProps, pProps = NULL;
846 0 : ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
847 : }
848 :
849 0 : if ( !out )
850 0 : m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION );
851 :
852 0 : if ( out )
853 0 : object = t.pEnv->NewGlobalRef( out );
854 :
855 0 : if ( object )
856 0 : m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url );
857 :
858 0 : m_aConnectionInfo = info;
859 : } //mID
860 : } //t.pEnv
861 0 : return object != NULL;
862 : }
863 : // -----------------------------------------------------------------------------
864 :
865 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|