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 : #include "java/lang/Class.hxx"
21 : #include <connectivity/CommonTools.hxx>
22 : #include <com/sun/star/uno/Exception.hpp>
23 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
24 : #include "java/tools.hxx"
25 : #include "java/sql/SQLException.hxx"
26 : #include <osl/mutex.hxx>
27 : #include <osl/thread.h>
28 : #include <com/sun/star/uno/Sequence.hxx>
29 : #include "java/LocalRef.hxx"
30 : #include "resource/jdbc_log.hrc"
31 :
32 : #include <comphelper/logging.hxx>
33 :
34 : #include <boost/scoped_ptr.hpp>
35 :
36 : using namespace connectivity;
37 : using namespace ::com::sun::star::uno;
38 : using namespace ::com::sun::star::beans;
39 : using namespace ::com::sun::star::sdbc;
40 : using namespace ::com::sun::star::container;
41 : using namespace ::com::sun::star::lang;
42 :
43 :
44 :
45 250469 : ::rtl::Reference< jvmaccess::VirtualMachine > getJavaVM2(const ::rtl::Reference< jvmaccess::VirtualMachine >& _rVM = ::rtl::Reference< jvmaccess::VirtualMachine >(),
46 : bool _bSet = false)
47 : {
48 250469 : static ::rtl::Reference< jvmaccess::VirtualMachine > s_VM;
49 250469 : if ( _rVM.is() || _bSet )
50 8 : s_VM = _rVM;
51 250469 : return s_VM;
52 : }
53 :
54 250461 : ::rtl::Reference< jvmaccess::VirtualMachine > java_lang_Object::getVM(const Reference<XComponentContext >& _rxContext)
55 : {
56 250461 : ::rtl::Reference< jvmaccess::VirtualMachine > xVM = getJavaVM2();
57 250461 : if ( !xVM.is() && _rxContext.is() )
58 4 : xVM = getJavaVM2(::connectivity::getJavaVM(_rxContext));
59 :
60 250461 : return xVM;
61 : }
62 :
63 250443 : SDBThreadAttach::SDBThreadAttach()
64 : : m_aGuard(java_lang_Object::getVM())
65 250443 : , pEnv(NULL)
66 : {
67 250443 : pEnv = m_aGuard.getEnvironment();
68 : OSL_ENSURE(pEnv,"Environment is nULL!");
69 250443 : }
70 :
71 250443 : SDBThreadAttach::~SDBThreadAttach()
72 : {
73 250443 : }
74 :
75 83508 : oslInterlockedCount& getJavaVMRefCount()
76 : {
77 : static oslInterlockedCount s_nRefCount = 0;
78 83508 : return s_nRefCount;
79 : }
80 :
81 27836 : void SDBThreadAttach::addRef()
82 : {
83 27836 : osl_atomic_increment(&getJavaVMRefCount());
84 27836 : }
85 :
86 27836 : void SDBThreadAttach::releaseRef()
87 : {
88 27836 : osl_atomic_decrement(&getJavaVMRefCount());
89 27836 : if ( getJavaVMRefCount() == 0 )
90 : {
91 4 : getJavaVM2(::rtl::Reference< jvmaccess::VirtualMachine >(),true);
92 : }
93 27836 : }
94 :
95 : // static variables of the class
96 : jclass java_lang_Object::theClass = 0;
97 :
98 0 : jclass java_lang_Object::getMyClass() const
99 : {
100 0 : if( !theClass )
101 0 : theClass = findMyClass("java/lang/Object");
102 0 : return theClass;
103 : }
104 : // the actual constructor
105 9 : java_lang_Object::java_lang_Object()
106 9 : : object( 0 )
107 : {
108 9 : SDBThreadAttach::addRef();
109 9 : }
110 :
111 : // the protected-constructor for the derived classes
112 14052 : java_lang_Object::java_lang_Object( JNIEnv * pXEnv, jobject myObj )
113 14052 : : object( NULL )
114 : {
115 14052 : SDBThreadAttach::addRef();
116 14052 : if( pXEnv && myObj )
117 13776 : object = pXEnv->NewGlobalRef( myObj );
118 14052 : }
119 :
120 14061 : java_lang_Object::~java_lang_Object()
121 : {
122 14061 : if( object )
123 : {
124 72 : SDBThreadAttach t;
125 72 : clearObject(*t.pEnv);
126 : }
127 14061 : SDBThreadAttach::releaseRef();
128 14061 : }
129 14070 : void java_lang_Object::clearObject(JNIEnv& rEnv)
130 : {
131 14070 : if( object )
132 : {
133 14070 : rEnv.DeleteGlobalRef( object );
134 14070 : object = NULL;
135 : }
136 14070 : }
137 :
138 285 : void java_lang_Object::clearObject()
139 : {
140 285 : if( object )
141 : {
142 276 : SDBThreadAttach t;
143 276 : clearObject(*t.pEnv);
144 : }
145 285 : }
146 : // the protected-constructor for the derived classes
147 9 : void java_lang_Object::saveRef( JNIEnv * pXEnv, jobject myObj )
148 : {
149 : OSL_ENSURE( myObj, "object in c++ -> Java Wrapper" );
150 9 : if( myObj )
151 9 : object = pXEnv->NewGlobalRef( myObj );
152 9 : }
153 :
154 :
155 0 : OUString java_lang_Object::toString() const
156 : {
157 : static jmethodID mID(NULL);
158 0 : return callStringMethod("toString",mID);
159 : }
160 :
161 :
162 : namespace
163 : {
164 207544 : bool lcl_translateJNIExceptionToUNOException(
165 : JNIEnv* _pEnvironment, const Reference< XInterface >& _rxContext, SQLException& _out_rException )
166 : {
167 207544 : jthrowable jThrow = _pEnvironment ? _pEnvironment->ExceptionOccurred() : NULL;
168 207544 : if ( !jThrow )
169 207543 : return false;
170 :
171 1 : _pEnvironment->ExceptionClear();
172 : // we have to clear the exception here because we want to handle it itself
173 :
174 1 : if ( _pEnvironment->IsInstanceOf( jThrow, java_sql_SQLException_BASE::st_getMyClass() ) )
175 : {
176 1 : boost::scoped_ptr< java_sql_SQLException_BASE > pException( new java_sql_SQLException_BASE( _pEnvironment, jThrow ) );
177 3 : _out_rException = SQLException( pException->getMessage(), _rxContext,
178 2 : pException->getSQLState(), pException->getErrorCode(), Any() );
179 1 : return true;
180 : }
181 0 : else if ( _pEnvironment->IsInstanceOf( jThrow, java_lang_Throwable::st_getMyClass() ) )
182 : {
183 0 : boost::scoped_ptr< java_lang_Throwable > pThrow( new java_lang_Throwable( _pEnvironment, jThrow ) );
184 : #if OSL_DEBUG_LEVEL > 0
185 : pThrow->printStackTrace();
186 : #endif
187 0 : OUString sMessage = pThrow->getMessage();
188 0 : if ( sMessage.isEmpty() )
189 0 : sMessage = pThrow->getLocalizedMessage();
190 0 : if( sMessage.isEmpty() )
191 0 : sMessage = pThrow->toString();
192 0 : _out_rException = SQLException( sMessage, _rxContext, OUString(), -1, Any() );
193 0 : return true;
194 : }
195 : else
196 0 : _pEnvironment->DeleteLocalRef( jThrow );
197 0 : return false;
198 : }
199 : }
200 :
201 :
202 1184 : void java_lang_Object::ThrowLoggedSQLException( const ::comphelper::ResourceBasedEventLogger& _rLogger, JNIEnv* _pEnvironment,
203 : const Reference< XInterface >& _rxContext )
204 : {
205 1184 : SQLException aException;
206 1184 : if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
207 : {
208 0 : _rLogger.log( ::com::sun::star::logging::LogLevel::SEVERE, STR_LOG_THROWING_EXCEPTION, aException.Message, aException.SQLState, aException.ErrorCode );
209 0 : throw aException;
210 1184 : }
211 1184 : }
212 :
213 206360 : void java_lang_Object::ThrowSQLException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext )
214 : {
215 206360 : SQLException aException;
216 206360 : if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) )
217 1 : throw aException;
218 206359 : }
219 :
220 27025 : void java_lang_Object::ThrowRuntimeException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext )
221 : {
222 : try
223 : {
224 27025 : ThrowSQLException(_pEnvironment, _rxContext);
225 : }
226 0 : catch (const SQLException& e)
227 : {
228 0 : throw WrappedTargetRuntimeException(e.Message, e.Context, makeAny(e));
229 : }
230 27025 : }
231 :
232 180336 : void java_lang_Object::obtainMethodId_throwSQL(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const
233 : {
234 180336 : if ( !_inout_MethodID )
235 : {
236 151 : _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature );
237 : OSL_ENSURE( _inout_MethodID, _pSignature );
238 151 : if ( !_inout_MethodID )
239 0 : throw SQLException();
240 : } // if ( !_inout_MethodID )
241 180336 : }
242 :
243 27025 : void java_lang_Object::obtainMethodId_throwRuntime(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const
244 : {
245 27025 : if ( !_inout_MethodID )
246 : {
247 13 : _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature );
248 : OSL_ENSURE( _inout_MethodID, _pSignature );
249 13 : if ( !_inout_MethodID )
250 0 : throw RuntimeException();
251 : } // if ( !_inout_MethodID )
252 27025 : }
253 :
254 :
255 59773 : bool java_lang_Object::callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
256 : {
257 59773 : jboolean out( sal_False );
258 :
259 59773 : SDBThreadAttach t;
260 : OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethod: no Java environment anymore!" );
261 59773 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()Z", _inout_MethodID);
262 : // call method
263 59773 : out = t.pEnv->CallBooleanMethod( object, _inout_MethodID );
264 59773 : ThrowSQLException( t.pEnv, NULL );
265 :
266 59773 : return out;
267 : }
268 :
269 258 : bool java_lang_Object::callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
270 : {
271 258 : jboolean out( sal_False );
272 258 : SDBThreadAttach t;
273 : OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethodWithIntArg: no Java environment anymore!" );
274 258 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)Z", _inout_MethodID);
275 : // call method
276 258 : out = t.pEnv->CallBooleanMethod( object, _inout_MethodID, _nArgument );
277 258 : ThrowSQLException( t.pEnv, NULL );
278 :
279 258 : return out;
280 : }
281 :
282 13497 : jobject java_lang_Object::callResultSetMethod( JNIEnv& _rEnv,const char* _pMethodName, jmethodID& _inout_MethodID ) const
283 : {
284 : // call method
285 13497 : jobject out = callObjectMethod(&_rEnv,_pMethodName,"()Ljava/sql/ResultSet;", _inout_MethodID);
286 13496 : return out;
287 : }
288 :
289 676 : sal_Int32 java_lang_Object::callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const
290 : {
291 676 : SDBThreadAttach t;
292 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
293 676 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()I", _inout_MethodID);
294 : // call method
295 676 : jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) );
296 676 : ThrowSQLException( t.pEnv, NULL );
297 676 : return (sal_Int32)out;
298 : }
299 :
300 27016 : sal_Int32 java_lang_Object::callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const
301 : {
302 27016 : SDBThreadAttach t;
303 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
304 27016 : obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()I", _inout_MethodID);
305 : // call method
306 27016 : jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) );
307 27016 : ThrowRuntimeException(t.pEnv, NULL);
308 27016 : return (sal_Int32)out;
309 : }
310 :
311 14695 : sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const
312 : {
313 14695 : SDBThreadAttach t;
314 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
315 14695 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)I", _inout_MethodID);
316 : // call method
317 14695 : jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) );
318 14695 : ThrowSQLException( t.pEnv, NULL );
319 14695 : return (sal_Int32)out;
320 : }
321 :
322 0 : sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const
323 : {
324 0 : SDBThreadAttach t;
325 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
326 0 : obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)I", _inout_MethodID);
327 : // call method
328 0 : jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) );
329 0 : ThrowRuntimeException(t.pEnv, NULL);
330 0 : return (sal_Int32)out;
331 : }
332 :
333 27482 : void java_lang_Object::callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const
334 : {
335 27482 : SDBThreadAttach t;
336 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
337 27482 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()V", _inout_MethodID);
338 :
339 : // call method
340 27482 : t.pEnv->CallVoidMethod( object, _inout_MethodID );
341 27482 : ThrowSQLException( t.pEnv, NULL );
342 27482 : }
343 :
344 0 : void java_lang_Object::callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const
345 : {
346 0 : SDBThreadAttach t;
347 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
348 0 : obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()V", _inout_MethodID);
349 :
350 : // call method
351 0 : t.pEnv->CallVoidMethod( object, _inout_MethodID );
352 0 : ThrowRuntimeException(t.pEnv, NULL);
353 0 : }
354 :
355 0 : void java_lang_Object::callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
356 : {
357 0 : SDBThreadAttach t;
358 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
359 0 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)V", _inout_MethodID);
360 :
361 : // call method
362 0 : t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
363 0 : ThrowSQLException( t.pEnv, NULL );
364 0 : }
365 :
366 0 : void java_lang_Object::callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const
367 : {
368 0 : SDBThreadAttach t;
369 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
370 0 : obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)V", _inout_MethodID);
371 :
372 : // call method
373 0 : t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument );
374 0 : ThrowRuntimeException(t.pEnv, NULL);
375 0 : }
376 :
377 12 : void java_lang_Object::callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const
378 : {
379 12 : SDBThreadAttach t;
380 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
381 12 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID);
382 : // call method
383 12 : t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) );
384 12 : ThrowSQLException( t.pEnv, NULL );
385 12 : }
386 :
387 9 : void java_lang_Object::callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const
388 : {
389 9 : SDBThreadAttach t;
390 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
391 9 : obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID);
392 : // call method
393 9 : t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) );
394 9 : ThrowRuntimeException(t.pEnv, NULL);
395 9 : }
396 :
397 36 : OUString java_lang_Object::callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const
398 : {
399 36 : SDBThreadAttach t;
400 : OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" );
401 :
402 : // call method
403 36 : jstring out = static_cast<jstring>(callObjectMethod(t.pEnv,_pMethodName,"()Ljava/lang/String;", _inout_MethodID));
404 36 : return JavaString2String( t.pEnv, out );
405 : }
406 :
407 13595 : jobject java_lang_Object::callObjectMethod( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID ) const
408 : {
409 : // obtain method ID
410 13595 : obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
411 : // call method
412 13595 : jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID);
413 13596 : ThrowSQLException( _pEnv, NULL );
414 13594 : return out;
415 : }
416 :
417 :
418 48665 : jobject java_lang_Object::callObjectMethodWithIntArg( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
419 : {
420 48665 : obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID);
421 : // call method
422 48665 : jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID,_nArgument );
423 48665 : ThrowSQLException( _pEnv, NULL );
424 48665 : return out;
425 : }
426 :
427 48629 : OUString java_lang_Object::callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const
428 : {
429 48629 : SDBThreadAttach t;
430 : OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" );
431 48629 : jstring out = static_cast<jstring>(callObjectMethodWithIntArg(t.pEnv,_pMethodName,"(I)Ljava/lang/String;",_inout_MethodID,_nArgument));
432 48629 : return JavaString2String( t.pEnv, out );
433 : }
434 :
435 0 : void java_lang_Object::callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const
436 : {
437 0 : SDBThreadAttach t;
438 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" );
439 0 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)V", _inout_MethodID);
440 :
441 0 : jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
442 : // call method
443 0 : t.pEnv->CallVoidMethod( object, _inout_MethodID , str.get());
444 0 : ThrowSQLException( t.pEnv, NULL );
445 0 : }
446 :
447 3 : sal_Int32 java_lang_Object::callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const
448 : {
449 3 : SDBThreadAttach t;
450 : OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethodWithStringArg: no Java environment anymore!" );
451 3 : obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)I", _inout_MethodID);
452 :
453 : //TODO: Check if the code below is needed
454 : //jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) );
455 : //{
456 : // jdbc::ContextClassLoaderScope ccl( t.env(),
457 : // m_pConnection ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(),
458 : // m_aLogger,
459 : // *this
460 : // );
461 :
462 6 : jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument));
463 : // call method
464 3 : jint out = t.pEnv->CallIntMethod( object, _inout_MethodID , str.get());
465 3 : ThrowSQLException( t.pEnv, NULL );
466 6 : return (sal_Int32)out;
467 : }
468 :
469 41 : jclass java_lang_Object::findMyClass(const char* _pClassName)
470 : {
471 : // the class must be fetched only once, therefore static
472 41 : SDBThreadAttach t;
473 41 : jclass tempClass = t.pEnv->FindClass(_pClassName); OSL_ENSURE(tempClass,"Java : FindClass nicht erfolgreich!");
474 41 : if(!tempClass)
475 : {
476 0 : t.pEnv->ExceptionDescribe();
477 0 : t.pEnv->ExceptionClear();
478 : }
479 41 : jclass globClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass ));
480 41 : t.pEnv->DeleteLocalRef( tempClass );
481 41 : return globClass;
482 : }
483 :
484 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|