Tag: cws_src680_dba24c
User: fs      
Date: 2007-10-15 13:33:17+0000
Modified:
   dba/connectivity/source/drivers/jdbc/JConnection.cxx

Log:
 #i82222# reworked SBs patch to use the driver classes class loader when 
constructing the connection, not when actually loading the system driver

File Changes:

Directory: /dba/connectivity/source/drivers/jdbc/
=================================================

File [changed]: JConnection.cxx
Url: 
http://dba.openoffice.org/source/browse/dba/connectivity/source/drivers/jdbc/JConnection.cxx?r1=1.6.2.2&r2=1.6.2.3
Delta lines:  +161 -265
-----------------------
--- JConnection.cxx     2007-10-10 20:40:46+0000        1.6.2.2
+++ JConnection.cxx     2007-10-15 13:33:15+0000        1.6.2.3
@@ -4,9 +4,9 @@
  *
  *  $RCSfile: JConnection.cxx,v $
  *
- *  $Revision: 1.6.2.2 $
+ *  $Revision: 1.6.2.3 $
  *
- *  last change: $Author: fs $ $Date: 2007/10/10 20:40:46 $
+ *  last change: $Author: fs $ $Date: 2007/10/15 13:33:15 $
  *
  *  The Contents of this file are made available subject to
  *  the terms of GNU Lesser General Public License Version 2.1.
@@ -35,13 +35,12 @@
 
 // MARKER(update_precomp.py): autogen include statement, do not remove
 #include "precompiled_connectivity.hxx"
-#ifndef _CONNECTIVITY_JAVA_SQL_CONNECTION_HXX_
+
 #include "java/sql/Connection.hxx"
-#endif
 #include "java/lang/Class.hxx"
-#ifndef _CONNECTIVITY_JAVA_TOOLS_HXX_
 #include "java/tools.hxx"
-#endif
+#include "java/ContextClassLoader.hxx"
+
 #ifndef _CONNECTIVITY_JAVA_SQL_DATABASEMETADATA_HXX_
 #include "java/sql/DatabaseMetaData.hxx"
 #endif
@@ -83,6 +82,7 @@
 #include <memory>
 
 using namespace connectivity;
+using namespace connectivity::jdbc;
 using namespace ::com::sun::star::uno;
 using namespace ::com::sun::star::beans;
 using namespace ::com::sun::star::sdbc;
@@ -91,27 +91,6 @@
 
 namespace {
 
-template< typename T > struct LocalRef {
-    explicit LocalRef(JNIEnv * environment):
-        object(NULL), m_environment(environment) {}
-
-    ~LocalRef() { if (object != NULL) m_environment->DeleteLocalRef(object); }
-
-    T release() {
-        T t = object;
-        object = NULL;
-        return t;
-    }
-
-    T object;
-
-private:
-    LocalRef(LocalRef &); // not defined
-    void operator =(LocalRef &); // not defined
-
-    JNIEnv *& m_environment;
-};
-
 struct ClassMapEntry {
     ClassMapEntry(
         rtl::OUString const & theClassPath, rtl::OUString const & 
theClassName):
@@ -139,6 +118,26 @@
     }
 };
 
+template < typename T >
+bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local )
+{
+    _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak 
) ) );
+
+    if ( !_inout_local.is() )
+    {
+        if ( _inout_local.env().ExceptionCheck())
+        {
+            return false;
+        }
+        else if ( _weak != NULL )
+        {
+            _inout_local.env().DeleteWeakGlobalRef( _weak );
+            _weak = NULL;
+        }
+    }
+    return true;
+}
+
 // Load a class.  A map from pairs of (classPath, name) to pairs of weak Java
 // references to (ClassLoader, Class) is maintained, so that a class is only
 // loaded once.
@@ -159,7 +158,7 @@
 //
 // If false is returned, a (still pending) JNI exception occurred.
 bool loadClass(
-    Reference< XComponentContext > const & context, JNIEnv * environment,
+    Reference< XComponentContext > const & context, JNIEnv& environment,
     rtl::OUString const & classPath, rtl::OUString const & name,
     LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr)
 {
@@ -176,164 +175,111 @@
     LocalRef< jclass > cl(environment);
     // Prune dangling weak references from the list while searching for a 
match,
     // so that the list cannot grow unbounded:
-    for (; i != d->map.end();) {
-        LocalRef< jobject > ocloader(environment);
-        ocloader.object = environment->NewLocalRef(i->classLoader);
-        if (ocloader.object == NULL) {
-            if (environment->ExceptionCheck()) {
+    for (; i != d->map.end();)
+    {
+        LocalRef< jobject > classLoader( environment );
+        if ( !getLocalFromWeakRef( i->classLoader, classLoader ) )
                 return false;
-            } else if (i->classLoader != NULL) {
-                environment->DeleteWeakGlobalRef(i->classLoader);
-                i->classLoader = NULL;
-            }
-        }
-        LocalRef< jclass > ocl(environment);
-        ocl.object = static_cast< jclass >(
-            environment->NewLocalRef(i->classObject));
-        if (ocl.object == NULL) {
-            if (environment->ExceptionCheck()) {
+
+        LocalRef< jclass > classObject( environment );
+        if ( !getLocalFromWeakRef( i->classObject, classObject ) )
                 return false;
-            } else if (i->classObject != NULL) {
-                environment->DeleteWeakGlobalRef(i->classObject);
-                i->classObject = NULL;
-            }
-        }
-        if (ocloader.object == NULL && ocl.object == NULL) {
+
+        if ( !classLoader.is() && !classObject.is() )
+        {
             i = d->map.erase(i);
-        } else if (i->classPath == classPath && i->className == name) {
-            cloader.object = ocloader.release();
-            cl.object = ocl.release();
+        }
+        else if ( i->classPath == classPath && i->className == name )
+        {
+            cloader.set( classLoader.release() );
+            cl.set( classObject.release() );
             break;
-        } else {
+        }
+        else
+        {
             ++i;
         }
     }
-    if (cloader.object == NULL || cl.object == NULL) {
-        if (i == d->map.end()) {
+    if ( !cloader.is() || !cl.is() )
+    {
+        if ( i == d->map.end() )
+        {
             // Push a new ClassMapEntry (which can potentially fail) before
             // loading the class, so that it never happens that a class is
             // loaded but not added to the map (which could have effects on the
             // JVM that are not easily undone).  If the pushed ClassMapEntry is
             // not used after all (return false, etc.) it will be pruned on 
next
             // call because its classLoader/classObject are null:
-            d->map.push_front(ClassMapEntry(classPath, name));
+            d->map.push_front( ClassMapEntry( classPath, name ) );
             i = d->map.begin();
         }
-        LocalRef< jclass > clClass(environment);
-        clClass.object = environment->FindClass("java/net/URLClassLoader");
-        if (clClass.object == NULL) {
+
+        LocalRef< jclass > clClass( environment );
+        clClass.set( environment.FindClass( "java/net/URLClassLoader" ) );
+        if ( !clClass.is() )
             return false;
-        }
+
         jweak wcloader = NULL;
-        if (cloader.object == NULL) {
-            jmethodID ctorLoader(
-                environment->GetMethodID(
-                    clClass.object, "<init>", "([Ljava/net/URL;)V"));
-            if (ctorLoader == NULL) {
+        if (!cloader.is())
+        {
+            jmethodID ctorLoader( environment.GetMethodID( clClass.get(), 
"<init>", "([Ljava/net/URL;)V" ) );
+            if (ctorLoader == NULL)
                 return false;
-            }
-            LocalRef< jobjectArray > arr(environment);
-            arr.object = jvmaccess::ClassPath::translateToUrls(
-                context, environment, classPath);
-            if (arr.object == NULL) {
+
+            LocalRef< jobjectArray > arr( environment );
+            arr.set( jvmaccess::ClassPath::translateToUrls( context, 
&environment, classPath ) );
+            if ( !arr.is() )
                 return false;
-            }
+
             jvalue arg;
-            arg.l = arr.object;
-            cloader.object = environment->NewObjectA(
-                clClass.object, ctorLoader, &arg);
-            if (cloader.object == NULL) {
+            arg.l = arr.get();
+            cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, 
&arg ) );
+            if ( !cloader.is() )
                 return false;
-            }
-            wcloader = environment->NewWeakGlobalRef(cloader.object);
-            if (wcloader == NULL) {
+
+            wcloader = environment.NewWeakGlobalRef( cloader.get() );
+            if ( wcloader == NULL )
                 return false;
             }
-        }
+
         jweak wcl = NULL;
-        if (cl.object == NULL) {
-            jmethodID methLoadClass(
-                environment->GetMethodID(
-                    clClass.object, "loadClass",
-                    "(Ljava/lang/String;)Ljava/lang/Class;"));
-            if (methLoadClass == NULL) {
+        if ( !cl.is() )
+        {
+            jmethodID methLoadClass( environment.GetMethodID( clClass.get(), 
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) );
+            if ( methLoadClass == NULL )
                 return false;
-            }
-            LocalRef< jstring > str(environment);
-            str.object = environment->NewString(
-                static_cast< jchar const * >(name.getStr()),
-                static_cast< jsize >(name.getLength()));
-            if (str.object == NULL) {
+
+            LocalRef< jstring > str( environment );
+            str.set( convertwchar_tToJavaString( &environment, name ) );
+            if ( !str.is() )
                 return false;
-            }
+
             jvalue arg;
-            arg.l = str.object;
-            cl.object = static_cast< jclass > (
-                environment->CallObjectMethodA(
-                    cloader.object, methLoadClass, &arg));
-            if (cl.object == NULL) {
+            arg.l = str.get();
+            cl.set( static_cast< jclass >( environment.CallObjectMethodA( 
cloader.get(), methLoadClass, &arg ) ) );
+            if ( !cl.is() )
                 return false;
-            }
-            wcl = environment->NewWeakGlobalRef(cl.object);
-            if (wcl == NULL) {
+
+            wcl = environment.NewWeakGlobalRef( cl.get() );
+            if ( wcl == NULL )
                 return false;
             }
-        }
-        if (wcloader != NULL) {
+
+        if ( wcloader != NULL)
+        {
             i->classLoader = wcloader;
         }
-        if (wcl != NULL) {
+        if ( wcl != NULL )
+        {
             i->classObject = wcl;
         }
     }
-    classLoaderPtr->object = cloader.release();
-    classPtr->object = cl.release();
+
+    classLoaderPtr->set( cloader.release() );
+    classPtr->set( cl.release() );
     return true;
 }
 
-// simulate a Java
-//   finally {
-//     Thread.currentThread.setContextClassLoader(oldContextClassLoader); }
-class ContextClassLoaderScope {
-public:
-    ContextClassLoaderScope(
-        JNIEnv * environment, LocalRef< jobject > & currentThread,
-        LocalRef< jobject > & oldContextClassLoader):
-        m_environment(environment), m_currentThread(currentThread),
-        m_oldContextClassLoader(oldContextClassLoader), m_active(false) {}
-
-    ~ContextClassLoaderScope() { pop(true); }
-
-    void activate(jmethodID setContextClassLoaderMethod) {
-        m_setContextClassLoaderMethod = setContextClassLoaderMethod;
-        m_active = true;
-    }
-
-    void pop() { pop(false); }
-
-private:
-    ContextClassLoaderScope(ContextClassLoaderScope &); // not defined
-    void operator =(ContextClassLoaderScope &); // not defined
-
-    void pop(bool clearExceptions) {
-        if (m_active) {
-            m_active = false;
-            m_environment->CallObjectMethod(
-                m_currentThread.object, m_setContextClassLoaderMethod,
-                m_oldContextClassLoader.object);
-            if (clearExceptions) {
-                m_environment->ExceptionClear();
-            }
-        }
-    }
-
-    JNIEnv *& m_environment;
-    LocalRef< jobject > & m_currentThread;
-    LocalRef< jobject > & m_oldContextClassLoader;
-    jmethodID m_setContextClassLoaderMethod;
-    bool m_active;
-};
-
 }
 
 
//------------------------------------------------------------------------------
@@ -350,6 +296,7 @@
     ,m_xMetaData(NULL)
     ,m_pDriver( &_rDriver )
     ,m_pDriverobject(NULL)
+    ,m_pDriverClassLoader()
     ,m_Driver_theClass(NULL)
     ,m_aLogger( _rDriver.getLogger() )
     ,m_bParameterSubstitution(sal_False)
@@ -960,12 +907,15 @@
        return Any();
 }
 // 
-----------------------------------------------------------------------------
-void java_sql_Connection::loadDriverFromProperties(
-        const Sequence< PropertyValue >& info, ::rtl::OUString& 
_rsGeneratedValueStatement,
-               sal_Bool& _rbAutoRetrievingEnabled, sal_Bool& 
_bParameterSubstitution, sal_Bool& _bIgnoreDriverPrivileges )
+void java_sql_Connection::loadDriverFromProperties( const Sequence< 
PropertyValue >& info )
 {
+    // contains the statement which should be used when query for 
automatically generated values
+       ::rtl::OUString         sGeneratedValueStatement;
+    // set to <TRUE/> when we should allow to query for generated values
+       sal_Bool                        bAutoRetrievingEnabled = sal_False;
+
        // first try if the jdbc driver is alraedy registered at the driver 
manager
-    SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java Enviroment geloescht worden!");
+    SDBThreadAttach t;
        try
        {
         const PropertyValue* pJavaDriverClass = 0;
@@ -984,23 +934,25 @@
             }
                        else 
if(!pBegin->Name.compareToAscii("IsAutoRetrievingEnabled"))
                        {
-                               OSL_VERIFY( pBegin->Value >>= 
_rbAutoRetrievingEnabled );
+                               OSL_VERIFY( pBegin->Value >>= 
bAutoRetrievingEnabled );
                        }
                        else 
if(!pBegin->Name.compareToAscii("AutoRetrievingStatement"))
                        {
-                               OSL_VERIFY( pBegin->Value >>= 
_rsGeneratedValueStatement );
+                               OSL_VERIFY( pBegin->Value >>= 
sGeneratedValueStatement );
                        }
                        else 
if(!pBegin->Name.compareToAscii("ParameterNameSubstitution"))
                        {
-                               OSL_VERIFY( pBegin->Value >>= 
_bParameterSubstitution );
+                               OSL_VERIFY( pBegin->Value >>= 
m_bParameterSubstitution );
                        }
                        else 
if(!pBegin->Name.compareToAscii("IgnoreDriverPrivileges"))
                        {
-                               OSL_VERIFY( pBegin->Value >>= 
_bIgnoreDriverPrivileges );
+                               OSL_VERIFY( pBegin->Value >>= 
m_bIgnoreDriverPrivileges );
                        }
                }
         if ( !object && pJavaDriverClass != 0 )
         {
+            m_pDriverClassLoader.reset();
+
             // here I try to find the class for jdbc driver
             java_sql_SQLException_BASE::getMyClass();
             java_lang_Throwable::getMyClass();
@@ -1017,7 +969,6 @@
                 m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, aStr );
                 // the driver manager holds the class of the driver for later 
use
                 ::std::auto_ptr< java_lang_Class > pDrvClass;
-                LocalRef< jobject > classLoader(t.pEnv);
                 if ( pJavaDriverClassPath == 0 )
                 {
                                        // if forName didn't find the class it 
will throw an exception
@@ -1027,94 +978,26 @@
                 {
                     ::rtl::OUString classpath;
                     OSL_VERIFY( pJavaDriverClassPath->Value >>= classpath );
-                    LocalRef< jclass > cl(t.pEnv);
+
+                    LocalRef< jclass > driverClass(t.env());
+                    LocalRef< jobject > driverClassLoader(t.env());
+
                     loadClass(
                         m_pDriver->getContext().getUNOContext(),
-                        t.pEnv, classpath, aStr, &classLoader, &cl );
-                    pDrvClass.reset(
-                        new java_lang_Class( t.pEnv, cl.release() )
-                    );
+                        t.env(), classpath, aStr, &driverClassLoader, 
&driverClass );
+
+                    m_pDriverClassLoader.set( driverClassLoader );
+                    pDrvClass.reset( new java_lang_Class( t.pEnv, 
driverClass.release() ) );
+
                     ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
                 }
                 if ( pDrvClass.get() )
                 {
-                    // In some cases (e.g.,
-                    // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
-                    // l. 249) the JavaDriverClassPath contains multiple jars,
-                    // as creating the JavaDriverClass instance requires
-                    // (reflective) access to those other jars.  Now, if the
-                    // JavaDriverClass is actually loaded by some parent class
-                    // loader (e.g., because its jar is also on the global
-                    // class path), it would still not have access to the
-                    // additional jars on the JavaDriverClassPath.  Hence, the
-                    // JavaDriverClassPath class loader is pushed as context
-                    // class loader around the JavaDriverClass instance
-                    // creation:
-                    {
-                        LocalRef< jclass > threadClass(t.pEnv);
-                        LocalRef< jobject > currentThread(t.pEnv);
-                        LocalRef< jobject > oldContextClassLoader(t.pEnv);
-                        ContextClassLoaderScope ccl(
-                            t.pEnv, currentThread, oldContextClassLoader);
-                        if (classLoader.object != NULL) {
-                            threadClass.object = t.pEnv->FindClass(
-                                "java/lang/Thread");
-                            if (threadClass.object == NULL) {
-                                ThrowLoggedSQLException(
-                                    m_aLogger, t.pEnv, *this);
-                                OSL_ASSERT(false); // unreachable
-                            }
-                            jmethodID currentThreadMethod(
-                                t.pEnv->GetStaticMethodID(
-                                    threadClass.object, "currentThread",
-                                    "()Ljava/lang/Thread;"));
-                            if (currentThreadMethod == NULL) {
-                                ThrowLoggedSQLException(
-                                    m_aLogger, t.pEnv, *this);
-                                OSL_ASSERT(false); // unreachable
-                            }
-                            currentThread.object =
-                                t.pEnv->CallStaticObjectMethod(
-                                    threadClass.object, currentThreadMethod);
-                            ThrowLoggedSQLException(m_aLogger, t.pEnv, *this);
-                            OSL_ASSERT(currentThread.object != NULL);
-                            jmethodID getContextClassLoaderMethod(
-                                t.pEnv->GetMethodID(
-                                    threadClass.object,
-                                    "getContextClassLoader",
-                                    "()Ljava/lang/ClassLoader;"));
-                            if (getContextClassLoaderMethod == NULL) {
-                                ThrowLoggedSQLException(
-                                    m_aLogger, t.pEnv, *this);
-                                OSL_ASSERT(false); // unreachable
-                            }
-                            oldContextClassLoader.object =
-                                t.pEnv->CallObjectMethod(
-                                    currentThread.object,
-                                    getContextClassLoaderMethod);
-                            ThrowLoggedSQLException(m_aLogger, t.pEnv, *this);
-                            jmethodID setContextClassLoaderMethod(
-                                t.pEnv->GetMethodID(
-                                    threadClass.object,
-                                    "setContextClassLoader",
-                                    "(Ljava/lang/ClassLoader;)V"));
-                            if (setContextClassLoaderMethod == NULL) {
-                                ThrowLoggedSQLException(
-                                    m_aLogger, t.pEnv, *this);
-                                OSL_ASSERT(false); // unreachable
-                            }
-                            ccl.activate(setContextClassLoaderMethod);
-                            t.pEnv->CallObjectMethod(
-                                currentThread.object,
-                                setContextClassLoaderMethod,
-                                classLoader.object);
-                        }
-                        LocalRef< jobject > o(t.pEnv);
-                        o.object = pDrvClass->newInstanceObject();
-                        ccl.pop();
-                        ThrowLoggedSQLException(m_aLogger, t.pEnv, *this);
-                        m_pDriverobject = o.release();
-                    }
+                    LocalRef< jobject > driverObject( t.env() );
+                    driverObject.set( pDrvClass->newInstanceObject() );
+                    ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+                    m_pDriverobject = driverObject.release();
+
                     if( t.pEnv && m_pDriverobject )
                         m_pDriverobject = t.pEnv->NewGlobalRef( 
m_pDriverobject );
                     if( t.pEnv )
@@ -1133,13 +1016,24 @@
        }
        catch(SQLException& e)
        {
-               throw SQLException(::rtl::OUString::createFromAscii("The 
specified driver could not be 
loaded!"),*this,::rtl::OUString(),1000,makeAny(e));
+               throw SQLException(
+            ::rtl::OUString::createFromAscii( "The specified driver could not 
be loaded." ),
+                // TODO: resource
+            *this,
+            ::rtl::OUString(),
+            1000,
+            makeAny(e)
+        );
        }
        catch(Exception&)
        {
                
::dbtools::throwGenericSQLException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("The
 specified driver could not be loaded!")) ,*this);
        }
+
+       enableAutoRetrievingEnabled( bAutoRetrievingEnabled );
+       setAutoRetrievingStatement( sGeneratedValueStatement );
 }
+
 // 
-----------------------------------------------------------------------------
 sal_Bool java_sql_Connection::construct(const ::rtl::OUString& url,
                                                                        const 
Sequence< PropertyValue >& info)
@@ -1154,12 +1048,7 @@
        if ( !t.pEnv )
                        throw SQLException(::rtl::OUString::createFromAscii("No 
Java installation could be found. Please check your 
installation!"),*this,::rtl::OUString::createFromAscii("S1000"),1000 ,Any());
 
-       ::rtl::OUString         sGeneratedValueStatement; // contains the 
statement which should be used when query for automatically generated values
-       sal_Bool                        bAutoRetrievingEnabled = sal_False; // 
set to <TRUE/> when we should allow to query for generated values
-       
loadDriverFromProperties(info,sGeneratedValueStatement,bAutoRetrievingEnabled,m_bParameterSubstitution,m_bIgnoreDriverPrivileges);
-
-       enableAutoRetrievingEnabled(bAutoRetrievingEnabled);
-       setAutoRetrievingStatement(sGeneratedValueStatement);
+       loadDriverFromProperties( info );
 
        if ( t.pEnv && m_Driver_theClass && m_pDriverobject )
        {
@@ -1179,24 +1068,31 @@
                        java_util_Properties* pProps = 
createStringPropertyArray(info);
                        args[1].l = pProps->getJavaObject();
 
-                       jobject out = t.pEnv->CallObjectMethod( 
m_pDriverobject, mID, args[0].l,args[1].l );
-            if ( !out )
-                m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION 
);
+            LocalRef< jobject > ensureDelete( t.env(), args[0].l );
 
-                       try
+            jobject out = NULL;
+            // In some cases (e.g.,
+            // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24
+            // l. 249) the JavaDriverClassPath contains multiple jars,
+            // as creating the JavaDriverClass instance requires
+            // (reflective) access to those other jars.  Now, if the
+            // JavaDriverClass is actually loaded by some parent class
+            // loader (e.g., because its jar is also on the global
+            // class path), it would still not have access to the
+            // additional jars on the JavaDriverClassPath.  Hence, the
+            // JavaDriverClassPath class loader is pushed as context
+            // class loader around the JavaDriverClass instance
+            // creation:
+            // #i82222# / 2007-10-15
                        {
+                ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), 
getLogger(), *this );
+                out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, 
args[0].l,args[1].l );
+                delete pProps, pProps = NULL;
                                ThrowLoggedSQLException( m_aLogger, t.pEnv, 
*this );
                        }
-                       catch(const SQLException& )
-                       {
-                               t.pEnv->DeleteLocalRef((jstring)args[0].l);
-                               delete pProps;
-                               throw;
-                       }
-                       // und aufraeumen
-                       t.pEnv->DeleteLocalRef((jstring)args[0].l);
-                       delete pProps;
-                       ThrowLoggedSQLException( m_aLogger, t.pEnv, *this );
+
+            if ( !out )
+                m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION 
);
 
                        if ( out )
                                object = t.pEnv->NewGlobalRef( out );




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to