xref: /trunk/main/dbaccess/source/core/dataaccess/datasource.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_dbaccess.hxx"
30 
31 #include "datasource.hxx"
32 #include "module_dba.hxx"
33 #include "userinformation.hxx"
34 #include "commandcontainer.hxx"
35 #include "dbastrings.hrc"
36 #include "core_resource.hxx"
37 #include "core_resource.hrc"
38 #include "connection.hxx"
39 #include "SharedConnection.hxx"
40 #include "databasedocument.hxx"
41 #include "OAuthenticationContinuation.hxx"
42 
43 
44 /** === begin UNO includes === **/
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/beans/PropertyState.hpp>
48 #include <com/sun/star/beans/XPropertyContainer.hpp>
49 #include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
50 #include <com/sun/star/document/XEventBroadcaster.hpp>
51 #include <com/sun/star/embed/XTransactedObject.hpp>
52 #include <com/sun/star/lang/DisposedException.hpp>
53 #include <com/sun/star/reflection/XProxyFactory.hpp>
54 #include <com/sun/star/sdbc/XDriverAccess.hpp>
55 #include <com/sun/star/sdbc/XDriverManager.hpp>
56 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
57 #include <com/sun/star/ucb/AuthenticationRequest.hpp>
58 #include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
59 #include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
60 #include <com/sun/star/view/XPrintable.hpp>
61 /** === end UNO includes === **/
62 
63 #include <comphelper/extract.hxx>
64 #include <comphelper/guarding.hxx>
65 #include <comphelper/interaction.hxx>
66 #include <comphelper/namedvaluecollection.hxx>
67 #include <comphelper/property.hxx>
68 #include <comphelper/seqstream.hxx>
69 #include <comphelper/sequence.hxx>
70 #include <comphelper/string.hxx>
71 #include <connectivity/dbexception.hxx>
72 #include <connectivity/dbtools.hxx>
73 #include <cppuhelper/typeprovider.hxx>
74 #include <tools/debug.hxx>
75 #include <tools/diagnose_ex.h>
76 #include <tools/urlobj.hxx>
77 #include <typelib/typedescription.hxx>
78 #include <unotools/confignode.hxx>
79 #include <unotools/sharedunocomponent.hxx>
80 #include <rtl/logfile.hxx>
81 #include <rtl/digest.h>
82 #include <algorithm>
83 
84 using namespace ::com::sun::star::sdbc;
85 using namespace ::com::sun::star::sdbcx;
86 using namespace ::com::sun::star::sdb;
87 using namespace ::com::sun::star::beans;
88 using namespace ::com::sun::star::uno;
89 using namespace ::com::sun::star::lang;
90 using namespace ::com::sun::star::embed;
91 using namespace ::com::sun::star::container;
92 using namespace ::com::sun::star::util;
93 using namespace ::com::sun::star::io;
94 using namespace ::com::sun::star::task;
95 using namespace ::com::sun::star::ucb;
96 using namespace ::com::sun::star::frame;
97 using namespace ::com::sun::star::reflection;
98 using namespace ::cppu;
99 using namespace ::osl;
100 using namespace ::vos;
101 using namespace ::dbtools;
102 using namespace ::comphelper;
103 namespace css = ::com::sun::star;
104 
105 //........................................................................
106 namespace dbaccess
107 {
108 //........................................................................
109 
110 //============================================================
111 //= FlushNotificationAdapter
112 //============================================================
113 typedef ::cppu::WeakImplHelper1< XFlushListener > FlushNotificationAdapter_Base;
114 /** helper class which implements a XFlushListener, and forwards all
115     notification events to another XFlushListener
116 
117     The speciality is that the foreign XFlushListener instance, to which
118     the notifications are forwarded, is held weak.
119 
120     Thus, the class can be used with XFlushable instance which hold
121     their listeners with a hard reference, if you simply do not *want*
122     to be held hard-ref-wise.
123 */
124 class FlushNotificationAdapter : public FlushNotificationAdapter_Base
125 {
126 private:
127     WeakReference< XFlushable >     m_aBroadcaster;
128     WeakReference< XFlushListener > m_aListener;
129 
130 public:
131     static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
132     {
133         Reference< XFlushListener > xAdapter( new FlushNotificationAdapter( _rxBroadcaster, _rxListener ) );
134     }
135 
136 protected:
137     FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
138     ~FlushNotificationAdapter();
139 
140     void SAL_CALL impl_dispose( bool _bRevokeListener );
141 
142 protected:
143     // XFlushListener
144     virtual void SAL_CALL flushed( const ::com::sun::star::lang::EventObject& rEvent ) throw (::com::sun::star::uno::RuntimeException);
145     // XEventListener
146     virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
147 };
148 
149 //------------------------------------------------------------
150 DBG_NAME( FlushNotificationAdapter )
151 //------------------------------------------------------------
152 FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
153     :m_aBroadcaster( _rxBroadcaster )
154     ,m_aListener( _rxListener )
155 {
156     DBG_CTOR( FlushNotificationAdapter, NULL );
157     DBG_ASSERT( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
158 
159     osl_incrementInterlockedCount( &m_refCount );
160     {
161         if ( _rxBroadcaster.is() )
162             _rxBroadcaster->addFlushListener( this );
163     }
164     osl_decrementInterlockedCount( &m_refCount );
165     DBG_ASSERT( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
166 }
167 
168 //------------------------------------------------------------
169 FlushNotificationAdapter::~FlushNotificationAdapter()
170 {
171     DBG_DTOR( FlushNotificationAdapter, NULL );
172 }
173 
174 //--------------------------------------------------------------------
175 void SAL_CALL FlushNotificationAdapter::impl_dispose( bool _bRevokeListener )
176 {
177     Reference< XFlushListener > xKeepAlive( this );
178 
179     if ( _bRevokeListener )
180     {
181         Reference< XFlushable > xFlushable( m_aBroadcaster );
182         if ( xFlushable.is() )
183             xFlushable->removeFlushListener( this );
184     }
185 
186     m_aListener = Reference< XFlushListener >();
187     m_aBroadcaster = Reference< XFlushable >();
188 }
189 
190 //--------------------------------------------------------------------
191 void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent ) throw (RuntimeException)
192 {
193     Reference< XFlushListener > xListener( m_aListener );
194     if ( xListener.is() )
195         xListener->flushed( rEvent );
196     else
197         impl_dispose( true );
198 }
199 
200 //--------------------------------------------------------------------
201 void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source ) throw (RuntimeException)
202 {
203     Reference< XFlushListener > xListener( m_aListener );
204     if ( xListener.is() )
205         xListener->disposing( Source );
206 
207     impl_dispose( true );
208 }
209 
210 //--------------------------------------------------------------------------
211 OAuthenticationContinuation::OAuthenticationContinuation()
212     :m_bRemberPassword(sal_True),   // TODO: a meaningfull default
213     m_bCanSetUserName(sal_True)
214 {
215 }
216 
217 //--------------------------------------------------------------------------
218 sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm(  ) throw(RuntimeException)
219 {
220     return sal_False;
221 }
222 
223 //--------------------------------------------------------------------------
224 void SAL_CALL OAuthenticationContinuation::setRealm( const ::rtl::OUString& /*Realm*/ ) throw(RuntimeException)
225 {
226     DBG_ERROR("OAuthenticationContinuation::setRealm: not supported!");
227 }
228 
229 //--------------------------------------------------------------------------
230 sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName(  ) throw(RuntimeException)
231 {
232     // we alwas allow this, even if the database document is read-only. In this case,
233     // it's simply that the user cannot store the new user name.
234     return m_bCanSetUserName;
235 }
236 
237 //--------------------------------------------------------------------------
238 void SAL_CALL OAuthenticationContinuation::setUserName( const ::rtl::OUString& _rUser ) throw(RuntimeException)
239 {
240     m_sUser = _rUser;
241 }
242 
243 //--------------------------------------------------------------------------
244 sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword(  ) throw(RuntimeException)
245 {
246     return sal_True;
247 }
248 
249 //--------------------------------------------------------------------------
250 void SAL_CALL OAuthenticationContinuation::setPassword( const ::rtl::OUString& _rPassword ) throw(RuntimeException)
251 {
252     m_sPassword = _rPassword;
253 }
254 
255 //--------------------------------------------------------------------------
256 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault ) throw(RuntimeException)
257 {
258     Sequence< RememberAuthentication > aReturn(1);
259     _reDefault = aReturn[0] = RememberAuthentication_SESSION;
260     return aReturn;
261 }
262 
263 //--------------------------------------------------------------------------
264 void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) throw(RuntimeException)
265 {
266     m_bRemberPassword = (RememberAuthentication_NO != _eRemember);
267 }
268 
269 //--------------------------------------------------------------------------
270 sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount(  ) throw(RuntimeException)
271 {
272     return sal_False;
273 }
274 
275 //--------------------------------------------------------------------------
276 void SAL_CALL OAuthenticationContinuation::setAccount( const ::rtl::OUString& ) throw(RuntimeException)
277 {
278     DBG_ERROR("OAuthenticationContinuation::setAccount: not supported!");
279 }
280 
281 //--------------------------------------------------------------------------
282 Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault ) throw(RuntimeException)
283 {
284     Sequence < RememberAuthentication > aReturn(1);
285     aReturn[0] = RememberAuthentication_NO;
286     _reDefault = RememberAuthentication_NO;
287     return aReturn;
288 }
289 
290 //--------------------------------------------------------------------------
291 void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) throw(RuntimeException)
292 {
293     DBG_ERROR("OAuthenticationContinuation::setRememberAccount: not supported!");
294 }
295 
296 /** The class OSharedConnectionManager implements a structure to share connections.
297     It owns the master connections which will be disposed when the last connection proxy is gone.
298 */
299 typedef ::cppu::WeakImplHelper1< XEventListener > OConnectionHelper_BASE;
300 // need to hold the digest
301 struct TDigestHolder
302 {
303     sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
304     TDigestHolder()
305     {
306         m_pBuffer[0] = 0;
307     }
308 
309 };
310 
311 class OSharedConnectionManager : public OConnectionHelper_BASE
312 {
313 
314      // contains the currently used master connections
315     typedef struct
316     {
317         Reference< XConnection >    xMasterConnection;
318         oslInterlockedCount         nALiveCount;
319     } TConnectionHolder;
320 
321     // the less-compare functor, used for the stl::map
322     struct TDigestLess : public ::std::binary_function< TDigestHolder, TDigestHolder, bool>
323     {
324         bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
325         {
326             sal_uInt32 i;
327             for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
328                 ;
329             return i < RTL_DIGEST_LENGTH_SHA1;
330         }
331     };
332 
333     typedef ::std::map< TDigestHolder,TConnectionHolder,TDigestLess>        TConnectionMap;      // holds the master connections
334     typedef ::std::map< Reference< XConnection >,TConnectionMap::iterator>  TSharedConnectionMap;// holds the shared connections
335 
336     ::osl::Mutex                m_aMutex;
337     TConnectionMap              m_aConnections;         // remeber the master connection in conjunction with the digest
338     TSharedConnectionMap        m_aSharedConnection;    // the shared connections with conjunction with an iterator into the connections map
339     Reference< XProxyFactory >  m_xProxyFactory;
340 
341 protected:
342     ~OSharedConnectionManager();
343 
344 public:
345     OSharedConnectionManager(const Reference< XMultiServiceFactory >& _rxServiceFactory);
346 
347     void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException);
348     Reference<XConnection> getConnection(   const rtl::OUString& url,
349                                             const rtl::OUString& user,
350                                             const rtl::OUString& password,
351                                             const Sequence< PropertyValue >& _aInfo,
352                                             ODatabaseSource* _pDataSource);
353     void addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter);
354 };
355 
356 DBG_NAME(OSharedConnectionManager)
357 OSharedConnectionManager::OSharedConnectionManager(const Reference< XMultiServiceFactory >& _rxServiceFactory)
358 {
359     DBG_CTOR(OSharedConnectionManager,NULL);
360     m_xProxyFactory.set(_rxServiceFactory->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.ProxyFactory"))),UNO_QUERY);
361 }
362 
363 OSharedConnectionManager::~OSharedConnectionManager()
364 {
365     DBG_DTOR(OSharedConnectionManager,NULL);
366 }
367 
368 void SAL_CALL OSharedConnectionManager::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException)
369 {
370     MutexGuard aGuard(m_aMutex);
371     Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
372     TSharedConnectionMap::iterator aFind = m_aSharedConnection.find(xConnection);
373     if ( m_aSharedConnection.end() != aFind )
374     {
375         osl_decrementInterlockedCount(&aFind->second->second.nALiveCount);
376         if ( !aFind->second->second.nALiveCount )
377         {
378             ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
379             m_aConnections.erase(aFind->second);
380         }
381         m_aSharedConnection.erase(aFind);
382     }
383 }
384 
385 Reference<XConnection> OSharedConnectionManager::getConnection( const rtl::OUString& url,
386                                         const rtl::OUString& user,
387                                         const rtl::OUString& password,
388                                         const Sequence< PropertyValue >& _aInfo,
389                                         ODatabaseSource* _pDataSource)
390 {
391     MutexGuard aGuard(m_aMutex);
392     TConnectionMap::key_type nId;
393     Sequence< PropertyValue > aInfoCopy(_aInfo);
394     sal_Int32 nPos = aInfoCopy.getLength();
395     aInfoCopy.realloc( nPos + 2 );
396     aInfoCopy[nPos].Name      = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableFilter"));
397     aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
398     aInfoCopy[nPos].Name      = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableTypeFilter"));
399     aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter; // #22377# OJ
400 
401     ::rtl::OUString sUser = user;
402     ::rtl::OUString sPassword = password;
403     if ((0 == sUser.getLength()) && (0 == sPassword.getLength()) && (0 != _pDataSource->m_pImpl->m_sUser.getLength()))
404     {   // ease the usage of this method. data source which are intended to have a user automatically
405         // fill in the user/password combination if the caller of this method does not specify otherwise
406         // 86951 - 05/08/2001 - frank.schoenheit@germany.sun.com
407         sUser = _pDataSource->m_pImpl->m_sUser;
408         if (0 != _pDataSource->m_pImpl->m_aPassword.getLength())
409             sPassword = _pDataSource->m_pImpl->m_aPassword;
410     }
411 
412     ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
413     TConnectionMap::iterator aIter = m_aConnections.find(nId);
414 
415     if ( m_aConnections.end() == aIter )
416     {
417         TConnectionHolder aHolder;
418         aHolder.nALiveCount = 0; // will be incremented by addListener
419         aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
420         aIter = m_aConnections.insert(TConnectionMap::value_type(nId,aHolder)).first;
421     }
422 
423     Reference<XConnection> xRet;
424     if ( aIter->second.xMasterConnection.is() )
425     {
426         Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection.get());
427         xRet = new OSharedConnection(xConProxy);
428         m_aSharedConnection.insert(TSharedConnectionMap::value_type(xRet,aIter));
429         addEventListener(xRet,aIter);
430     }
431 
432     return xRet;
433 }
434 void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection,TConnectionMap::iterator& _rIter)
435 {
436     Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
437     xComp->addEventListener(this);
438     OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
439     osl_incrementInterlockedCount(&_rIter->second.nALiveCount);
440 }
441 
442 //----------------------------------------------------------------------
443 namespace
444 {
445     //------------------------------------------------------------------
446     Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const ::rtl::OUString& _sUrl,
447         const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
448     {
449         if ( _xDriver.is() )
450         {
451             Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
452 
453             const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
454             const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
455 
456             ::std::vector< PropertyValue > aRet;
457 
458             for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
459             {
460                 sal_Bool bAllowSetting = sal_False;
461                 const AsciiPropertyValue* pSetting = _pKnownSettings;
462                 for ( ; pSetting->AsciiName; ++pSetting )
463                 {
464                     if ( !pDataSourceSetting->Name.compareToAscii( pSetting->AsciiName ) )
465                     {   // the particular data source setting is known
466 
467                         const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
468                         const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
469                         for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
470                         {
471                             if ( !pAllowedDriverSetting->Name.compareToAscii( pSetting->AsciiName ) )
472                             {   // the driver also allows this setting
473                                 bAllowSetting = sal_True;
474                                 break;
475                             }
476                         }
477                         break;
478                     }
479                 }
480                 if ( bAllowSetting || !pSetting->AsciiName )
481                 {   // if the driver allows this particular setting, or if the setting is completely unknown,
482                     // we pass it to the driver
483                     aRet.push_back( *pDataSourceSetting );
484                 }
485             }
486             if ( !aRet.empty() )
487                 return Sequence< PropertyValue >(&(*aRet.begin()),aRet.size());
488         }
489         return Sequence< PropertyValue >();
490     }
491 
492     //------------------------------------------------------------------
493     typedef ::std::map< ::rtl::OUString, sal_Int32 > PropertyAttributeCache;
494 
495     //------------------------------------------------------------------
496     struct IsDefaultAndNotRemoveable : public ::std::unary_function< PropertyValue, bool >
497     {
498     private:
499         const PropertyAttributeCache& m_rAttribs;
500 
501     public:
502         IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
503 
504         bool operator()( const PropertyValue& _rProp )
505         {
506             if ( _rProp.State != PropertyState_DEFAULT_VALUE )
507                 return false;
508 
509             bool bRemoveable = true;
510 
511             PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
512             OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
513             if ( pos != m_rAttribs.end() )
514                 bRemoveable = ( ( pos->second & PropertyAttribute::REMOVEABLE ) != 0 );
515 
516             return !bRemoveable;
517         }
518     };
519 }
520 //============================================================
521 //= ODatabaseContext
522 //============================================================
523 DBG_NAME(ODatabaseSource)
524 //--------------------------------------------------------------------------
525 extern "C" void SAL_CALL createRegistryInfo_ODatabaseSource()
526 {
527     static ::dba::OAutoRegistration< ODatabaseSource > aAutoRegistration;
528 }
529 
530 //--------------------------------------------------------------------------
531 ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
532             :ModelDependentComponent( _pImpl )
533             ,ODatabaseSource_Base( getMutex() )
534             ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
535             ,m_aBookmarks( *this, getMutex() )
536             ,m_aFlushListeners( getMutex() )
537 {
538     // some kind of default
539     DBG_CTOR(ODatabaseSource,NULL);
540     OSL_TRACE( "DS: ctor: %p: %p", this, m_pImpl.get() );
541 }
542 
543 //--------------------------------------------------------------------------
544 ODatabaseSource::~ODatabaseSource()
545 {
546     OSL_TRACE( "DS: dtor: %p: %p", this, m_pImpl.get() );
547     DBG_DTOR(ODatabaseSource,NULL);
548     if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
549     {
550         acquire();
551         dispose();
552     }
553 }
554 
555 //--------------------------------------------------------------------------
556 void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const ::rtl::OUString& _rNewName, DBContextAccess )
557 {
558     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setName" );
559     ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument.get() );
560 
561     ::osl::MutexGuard aGuard( rModelImpl.m_aMutex );
562     if ( rModelImpl.m_pImpl.is() )
563         rModelImpl.m_pImpl->m_sName = _rNewName;
564 }
565 
566 // com::sun::star::lang::XTypeProvider
567 //--------------------------------------------------------------------------
568 Sequence< Type > ODatabaseSource::getTypes() throw (RuntimeException)
569 {
570     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getTypes" );
571     OTypeCollection aPropertyHelperTypes(   ::getCppuType( (const Reference< XFastPropertySet > *)0 ),
572                                             ::getCppuType( (const Reference< XPropertySet > *)0 ),
573                                             ::getCppuType( (const Reference< XMultiPropertySet > *)0 ));
574 
575     return ::comphelper::concatSequences(
576         ODatabaseSource_Base::getTypes(),
577         aPropertyHelperTypes.getTypes()
578     );
579 }
580 
581 //--------------------------------------------------------------------------
582 Sequence< sal_Int8 > ODatabaseSource::getImplementationId() throw (RuntimeException)
583 {
584     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationId" );
585     static OImplementationId * pId = 0;
586     if (! pId)
587     {
588         MutexGuard aGuard( Mutex::getGlobalMutex() );
589         if (! pId)
590         {
591             static OImplementationId aId;
592             pId = &aId;
593         }
594     }
595     return pId->getImplementationId();
596 }
597 
598 // com::sun::star::uno::XInterface
599 //--------------------------------------------------------------------------
600 Any ODatabaseSource::queryInterface( const Type & rType ) throw (RuntimeException)
601 {
602     //RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::queryInterface" );
603     Any aIface = ODatabaseSource_Base::queryInterface( rType );
604     if ( !aIface.hasValue() )
605         aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
606     return aIface;
607 }
608 
609 //--------------------------------------------------------------------------
610 void ODatabaseSource::acquire() throw ()
611 {
612     ODatabaseSource_Base::acquire();
613 }
614 
615 //--------------------------------------------------------------------------
616 void ODatabaseSource::release() throw ()
617 {
618     ODatabaseSource_Base::release();
619 }
620 // -----------------------------------------------------------------------------
621 void SAL_CALL ODatabaseSource::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(RuntimeException)
622 {
623     if ( m_pImpl.is() )
624         m_pImpl->disposing(Source);
625 }
626 // XServiceInfo
627 //------------------------------------------------------------------------------
628 rtl::OUString ODatabaseSource::getImplementationName(  ) throw(RuntimeException)
629 {
630     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationName" );
631     return getImplementationName_static();
632 }
633 
634 //------------------------------------------------------------------------------
635 rtl::OUString ODatabaseSource::getImplementationName_static(  ) throw(RuntimeException)
636 {
637     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getImplementationName_static" );
638     return rtl::OUString::createFromAscii("com.sun.star.comp.dba.ODatabaseSource");
639 }
640 
641 //------------------------------------------------------------------------------
642 Sequence< ::rtl::OUString > ODatabaseSource::getSupportedServiceNames(  ) throw (RuntimeException)
643 {
644     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getSupportedServiceNames" );
645     return getSupportedServiceNames_static();
646 }
647 //------------------------------------------------------------------------------
648 Reference< XInterface > ODatabaseSource::Create( const Reference< XComponentContext >& _rxContext )
649 {
650     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::Create" );
651     ::comphelper::ComponentContext aContext( _rxContext );
652     Reference< XSingleServiceFactory > xDBContext( aContext.createComponent( (::rtl::OUString)SERVICE_SDB_DATABASECONTEXT ), UNO_QUERY_THROW );
653     return xDBContext->createInstance();
654 }
655 
656 //------------------------------------------------------------------------------
657 Sequence< ::rtl::OUString > ODatabaseSource::getSupportedServiceNames_static(  ) throw (RuntimeException)
658 {
659     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getSupportedServiceNames_static" );
660     Sequence< ::rtl::OUString > aSNS( 2 );
661     aSNS[0] = SERVICE_SDB_DATASOURCE;
662     aSNS[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sdb.DocumentDataSource"));
663     return aSNS;
664 }
665 
666 //------------------------------------------------------------------------------
667 sal_Bool ODatabaseSource::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
668 {
669     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::supportsService" );
670     return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0;
671 }
672 // OComponentHelper
673 //------------------------------------------------------------------------------
674 void ODatabaseSource::disposing()
675 {
676     OSL_TRACE( "DS: disp: %p, %p", this, m_pImpl.get() );
677     ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
678     OPropertySetHelper::disposing();
679 
680     EventObject aDisposeEvent(static_cast<XWeak*>(this));
681     m_aFlushListeners.disposeAndClear( aDisposeEvent );
682 
683     ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
684     ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
685     m_pImpl.clear();
686 }
687 //------------------------------------------------------------------------------
688 Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const ::rtl::OUString& _rUid, const ::rtl::OUString& _rPwd)
689 {
690     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::buildLowLevelConnection" );
691     Reference< XConnection > xReturn;
692 
693     Reference< XDriverManager > xManager;
694     if ( !m_pImpl->m_aContext.createComponent( "com.sun.star.sdbc.ConnectionPool", xManager ) )
695         // no connection pool installed, fall back to driver manager
696         m_pImpl->m_aContext.createComponent( "com.sun.star.sdbc.DriverManager", xManager );
697 
698     ::rtl::OUString sUser(_rUid);
699     ::rtl::OUString sPwd(_rPwd);
700     if ((0 == sUser.getLength()) && (0 == sPwd.getLength()) && (0 != m_pImpl->m_sUser.getLength()))
701     {   // ease the usage of this method. data source which are intended to have a user automatically
702         // fill in the user/password combination if the caller of this method does not specify otherwise
703         // 86951 - 05/08/2001 - frank.schoenheit@germany.sun.com
704         sUser = m_pImpl->m_sUser;
705         if (0 != m_pImpl->m_aPassword.getLength())
706             sPwd = m_pImpl->m_aPassword;
707     }
708 
709     sal_uInt16 nExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
710     if (xManager.is())
711     {
712         sal_Int32 nAdditionalArgs(0);
713         if (sUser.getLength()) ++nAdditionalArgs;
714         if (sPwd.getLength()) ++nAdditionalArgs;
715 
716         Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
717         sal_Int32 nArgPos = 0;
718         if (sUser.getLength())
719         {
720             aUserPwd[ nArgPos ].Name = ::rtl::OUString::createFromAscii("user");
721             aUserPwd[ nArgPos ].Value <<= sUser;
722             ++nArgPos;
723         }
724         if (sPwd.getLength())
725         {
726             aUserPwd[ nArgPos ].Name = ::rtl::OUString::createFromAscii("password");
727             aUserPwd[ nArgPos ].Value <<= sPwd;
728         }
729         Reference< XDriver > xDriver;
730         try
731         {
732             Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
733             if ( xAccessDrivers.is() )
734                 xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
735         }
736         catch( const Exception& )
737         {
738             DBG_ERROR( "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error!" );
739         }
740         if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
741         {
742             // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
743             // This is because registration nowadays happens at compile time (by adding respective configuration data),
744             // but acceptance is decided at runtime.
745             nExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
746         }
747         else
748         {
749             Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
750                 xDriver,
751                 m_pImpl->m_sConnectURL,
752                 m_pImpl->m_xSettings->getPropertyValues(),
753                 m_pImpl->getDefaultDataSourceSettings()
754             );
755 
756             if ( m_pImpl->isEmbeddedDatabase() )
757             {
758                 sal_Int32 nCount = aDriverInfo.getLength();
759                 aDriverInfo.realloc(nCount + 2 );
760                 aDriverInfo[nCount].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL"));
761                 aDriverInfo[nCount++].Value <<= m_pImpl->getURL();
762                 aDriverInfo[nCount].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Storage"));
763                 Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
764                 aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("database")),ElementModes::READWRITE);
765             }
766             if (nAdditionalArgs)
767                 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
768             else
769                 xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
770 
771             if ( m_pImpl->isEmbeddedDatabase() )
772             {
773                 // see ODatabaseSource::flushed for comment on why we register as FlushListener
774                 // at the connection
775                 Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
776                 if ( xFlushable.is() )
777                     FlushNotificationAdapter::installAdapter( xFlushable, this );
778             }
779         }
780     }
781     else
782         nExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
783 
784     if ( !xReturn.is() )
785     {
786         ::rtl::OUString sMessage = DBACORE_RESSTRING( nExceptionMessageId );
787 
788         SQLContext aContext;
789         aContext.Message = DBACORE_RESSTRING( RID_STR_CONNECTION_REQUEST );
790         ::comphelper::string::searchAndReplaceAsciiI( aContext.Message, "$name$", m_pImpl->m_sConnectURL );
791 
792         throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( aContext ) );
793     }
794 
795     return xReturn;
796 }
797 
798 // OPropertySetHelper
799 //------------------------------------------------------------------------------
800 Reference< XPropertySetInfo >  ODatabaseSource::getPropertySetInfo() throw (RuntimeException)
801 {
802     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getPropertySetInfo" );
803     return createPropertySetInfo( getInfoHelper() ) ;
804 }
805 
806 // comphelper::OPropertyArrayUsageHelper
807 //------------------------------------------------------------------------------
808 ::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
809 {
810     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::createArrayHelper" );
811     BEGIN_PROPERTY_HELPER(13)
812         DECL_PROP1(INFO,                        Sequence< PropertyValue >,  BOUND);
813         DECL_PROP1_BOOL(ISPASSWORDREQUIRED,                                 BOUND);
814         DECL_PROP1_BOOL(ISREADONLY,                                         READONLY);
815         DECL_PROP1(LAYOUTINFORMATION,           Sequence< PropertyValue >,  BOUND);
816         DECL_PROP1(NAME,                        ::rtl::OUString,            READONLY);
817         DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier,     READONLY, TRANSIENT);
818         DECL_PROP1(PASSWORD,                    ::rtl::OUString,            TRANSIENT);
819         DECL_PROP2_IFACE(SETTINGS,              XPropertySet,               BOUND, READONLY);
820         DECL_PROP1_BOOL(SUPPRESSVERSIONCL,                                  BOUND);
821         DECL_PROP1(TABLEFILTER,                 Sequence< ::rtl::OUString >,BOUND);
822         DECL_PROP1(TABLETYPEFILTER,             Sequence< ::rtl::OUString >,BOUND);
823         DECL_PROP1(URL,                         ::rtl::OUString,            BOUND);
824         DECL_PROP1(USER,                        ::rtl::OUString,            BOUND);
825     END_PROPERTY_HELPER();
826 }
827 
828 // cppu::OPropertySetHelper
829 //------------------------------------------------------------------------------
830 ::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
831 {
832     return *getArrayHelper();
833 }
834 
835 //------------------------------------------------------------------------------
836 sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) throw( IllegalArgumentException  )
837 {
838     //RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::convertFastPropertyValue" );
839     sal_Bool bModified(sal_False);
840     if ( m_pImpl.is() )
841     {
842         switch (nHandle)
843         {
844             case PROPERTY_ID_TABLEFILTER:
845                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
846                 break;
847             case PROPERTY_ID_TABLETYPEFILTER:
848                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
849                 break;
850             case PROPERTY_ID_USER:
851                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
852                 break;
853             case PROPERTY_ID_PASSWORD:
854                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
855                 break;
856             case PROPERTY_ID_ISPASSWORDREQUIRED:
857                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
858                 break;
859             case PROPERTY_ID_SUPPRESSVERSIONCL:
860                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
861                 break;
862             case PROPERTY_ID_LAYOUTINFORMATION:
863                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
864                 break;
865             case PROPERTY_ID_URL:
866             {
867                 bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
868             }   break;
869             case PROPERTY_ID_INFO:
870             {
871                 Sequence<PropertyValue> aValues;
872                 if (!(rValue >>= aValues))
873                     throw IllegalArgumentException();
874 
875                 const PropertyValue* valueEnd = aValues.getConstArray() + aValues.getLength();
876                 const PropertyValue* checkName = aValues.getConstArray();
877                 for ( ;checkName != valueEnd; ++checkName )
878                 {
879                     if ( !checkName->Name.getLength() )
880                         throw IllegalArgumentException();
881                 }
882 
883                 Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
884                 bModified = aSettings.getLength() != aValues.getLength();
885                 if ( !bModified )
886                 {
887                     const PropertyValue* pInfoIter = aSettings.getConstArray();
888                     const PropertyValue* checkValue = aValues.getConstArray();
889                     for ( ;!bModified && checkValue != valueEnd ; ++checkValue,++pInfoIter)
890                     {
891                         bModified = checkValue->Name != pInfoIter->Name;
892                         if ( !bModified )
893                         {
894                             bModified = !::comphelper::compare(checkValue->Value,pInfoIter->Value);
895                         }
896                     }
897                 }
898 
899                 rConvertedValue = rValue;
900                 rOldValue <<= aSettings;
901             }
902             break;
903             default:
904                 DBG_ERROR( "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
905         }
906     }
907     return bModified;
908 }
909 
910 //------------------------------------------------------------------------------
911 namespace
912 {
913     struct SelectPropertyName : public ::std::unary_function< PropertyValue, ::rtl::OUString >
914     {
915     public:
916         const ::rtl::OUString& operator()( const PropertyValue& _lhs )
917         {
918             return _lhs.Name;
919         }
920     };
921 
922     /** sets a new set of property values at a given property bag instance
923 
924         The methods takes a property bag, and a sequence of property values to set at this bag.
925         Upon return, every property which is not part of the given sequence is
926         <ul><li>removed from the bag, if it's a removeable property</li>
927             <li><em>or</em>reset to its default value, if it's not a removeable property</li>
928         </ul>.
929 
930         @param  _rxPropertyBag
931             the property bag to operate on
932         @param  _rAllNewPropertyValues
933             the new property values to set at the bag
934     */
935     void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyAccess >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
936     {
937         // sequences are ugly to operate on
938         typedef ::std::set< ::rtl::OUString >   StringSet;
939         StringSet aToBeSetPropertyNames;
940         ::std::transform(
941             _rAllNewPropertyValues.getConstArray(),
942             _rAllNewPropertyValues.getConstArray() + _rAllNewPropertyValues.getLength(),
943             ::std::insert_iterator< StringSet >( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
944             SelectPropertyName()
945         );
946 
947         try
948         {
949             // obtain all properties currently known at the bag
950             Reference< XPropertySet > xPropertySet( _rxPropertyBag, UNO_QUERY_THROW );
951             Reference< XPropertySetInfo > xPSI( xPropertySet->getPropertySetInfo(), UNO_QUERY_THROW );
952             Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
953 
954             Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
955             Reference< XPropertyContainer > xPropertyContainer( _rxPropertyBag, UNO_QUERY_THROW );
956 
957             // loop through them, and reset resp. default properties which are not to be set
958             const Property* pExistentProperty( aAllExistentProperties.getConstArray() );
959             const Property* pExistentPropertyEnd( aAllExistentProperties.getConstArray() + aAllExistentProperties.getLength() );
960             for ( ; pExistentProperty != pExistentPropertyEnd; ++pExistentProperty )
961             {
962                 if ( aToBeSetPropertyNames.find( pExistentProperty->Name ) != aToBeSetPropertyNames.end() )
963                     continue;
964 
965                 // this property is not to be set, but currently exists in the bag.
966                 // -> Remove, respectively default, it
967                 if ( ( pExistentProperty->Attributes & PropertyAttribute::REMOVEABLE ) != 0 )
968                     xPropertyContainer->removeProperty( pExistentProperty->Name );
969                 else
970                     xPropertyState->setPropertyToDefault( pExistentProperty->Name );
971             }
972 
973             // finally, set the new property values
974             _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
975         }
976         catch( const Exception& )
977         {
978             DBG_UNHANDLED_EXCEPTION();
979         }
980     }
981 }
982 
983 //------------------------------------------------------------------------------
984 void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) throw (Exception)
985 {
986     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setFastPropertyValue_NoBroadcast" );
987     if ( m_pImpl.is() )
988     {
989         switch(nHandle)
990         {
991             case PROPERTY_ID_TABLEFILTER:
992                 rValue >>= m_pImpl->m_aTableFilter;
993                 break;
994             case PROPERTY_ID_TABLETYPEFILTER:
995                 rValue >>= m_pImpl->m_aTableTypeFilter;
996                 break;
997             case PROPERTY_ID_USER:
998                 rValue >>= m_pImpl->m_sUser;
999                 // if the user name changed, reset the password
1000                 m_pImpl->m_aPassword = ::rtl::OUString();
1001                 break;
1002             case PROPERTY_ID_PASSWORD:
1003                 rValue >>= m_pImpl->m_aPassword;
1004                 break;
1005             case PROPERTY_ID_ISPASSWORDREQUIRED:
1006                 m_pImpl->m_bPasswordRequired = any2bool(rValue);
1007                 break;
1008             case PROPERTY_ID_SUPPRESSVERSIONCL:
1009                 m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
1010                 break;
1011             case PROPERTY_ID_URL:
1012                 rValue >>= m_pImpl->m_sConnectURL;
1013                 break;
1014             case PROPERTY_ID_INFO:
1015             {
1016                 Sequence< PropertyValue > aInfo;
1017                 OSL_VERIFY( rValue >>= aInfo );
1018                 lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
1019             }
1020             break;
1021             case PROPERTY_ID_LAYOUTINFORMATION:
1022                 rValue >>= m_pImpl->m_aLayoutInformation;
1023                 break;
1024         }
1025         m_pImpl->setModified(sal_True);
1026     }
1027 }
1028 
1029 //------------------------------------------------------------------------------
1030 void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
1031 {
1032     //RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getFastPropertyValue" );
1033     if ( m_pImpl.is() )
1034     {
1035         switch (nHandle)
1036         {
1037             case PROPERTY_ID_TABLEFILTER:
1038                 rValue <<= m_pImpl->m_aTableFilter;
1039                 break;
1040             case PROPERTY_ID_TABLETYPEFILTER:
1041                 rValue <<= m_pImpl->m_aTableTypeFilter;
1042                 break;
1043             case PROPERTY_ID_USER:
1044                 rValue <<= m_pImpl->m_sUser;
1045                 break;
1046             case PROPERTY_ID_PASSWORD:
1047                 rValue <<= m_pImpl->m_aPassword;
1048                 break;
1049             case PROPERTY_ID_ISPASSWORDREQUIRED:
1050                 rValue = bool2any(m_pImpl->m_bPasswordRequired);
1051                 break;
1052             case PROPERTY_ID_SUPPRESSVERSIONCL:
1053                 rValue = bool2any(m_pImpl->m_bSuppressVersionColumns);
1054                 break;
1055             case PROPERTY_ID_ISREADONLY:
1056                 rValue = bool2any(m_pImpl->m_bReadOnly);
1057                 break;
1058             case PROPERTY_ID_INFO:
1059             {
1060                 try
1061                 {
1062                     // collect the property attributes of all current settings
1063                     Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
1064                     Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_QUERY_THROW );
1065                     Sequence< Property > aSettings( xPST->getProperties() );
1066                     ::std::map< ::rtl::OUString, sal_Int32 > aPropertyAttributes;
1067                     for (   const Property* pSettings = aSettings.getConstArray();
1068                             pSettings != aSettings.getConstArray() + aSettings.getLength();
1069                             ++pSettings
1070                         )
1071                     {
1072                         aPropertyAttributes[ pSettings->Name ] = pSettings->Attributes;
1073                     }
1074 
1075                     // get all current settings with their values
1076                     Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
1077 
1078                     // transform them so that only property values which fulfill certain
1079                     // criterions survive
1080                     Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
1081                     const PropertyValue* pCopyEnd = ::std::remove_copy_if(
1082                         aValues.getConstArray(),
1083                         aValues.getConstArray() + aValues.getLength(),
1084                         aNonDefaultOrUserDefined.getArray(),
1085                         IsDefaultAndNotRemoveable( aPropertyAttributes )
1086                     );
1087                     aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() );
1088                     rValue <<= aNonDefaultOrUserDefined;
1089                 }
1090                 catch( const Exception& )
1091                 {
1092                     DBG_UNHANDLED_EXCEPTION();
1093                 }
1094             }
1095             break;
1096             case PROPERTY_ID_SETTINGS:
1097                 rValue <<= m_pImpl->m_xSettings;
1098                 break;
1099             case PROPERTY_ID_URL:
1100                 rValue <<= m_pImpl->m_sConnectURL;
1101                 break;
1102             case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
1103                 rValue <<= m_pImpl->getNumberFormatsSupplier();
1104                 break;
1105             case PROPERTY_ID_NAME:
1106                 rValue <<= m_pImpl->m_sName;
1107                 break;
1108             case PROPERTY_ID_LAYOUTINFORMATION:
1109                 rValue <<= m_pImpl->m_aLayoutInformation;
1110                 break;
1111             default:
1112                 DBG_ERROR("unknown Property");
1113         }
1114     }
1115 }
1116 
1117 // XDataSource
1118 //------------------------------------------------------------------------------
1119 void ODatabaseSource::setLoginTimeout(sal_Int32 seconds) throw( SQLException, RuntimeException )
1120 {
1121     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::setLoginTimeout" );
1122     ModelMethodGuard aGuard( *this );
1123     m_pImpl->m_nLoginTimeout = seconds;
1124 }
1125 
1126 //------------------------------------------------------------------------------
1127 sal_Int32 ODatabaseSource::getLoginTimeout(void) throw( SQLException, RuntimeException )
1128 {
1129     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getLoginTimeout" );
1130     ModelMethodGuard aGuard( *this );
1131     return m_pImpl->m_nLoginTimeout;
1132 }
1133 
1134 
1135 // XCompletedConnection
1136 //------------------------------------------------------------------------------
1137 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException)
1138 {
1139     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::connectWithCompletion" );
1140     return connectWithCompletion(_rxHandler,sal_False);
1141 }
1142 // -----------------------------------------------------------------------------
1143 Reference< XConnection > ODatabaseSource::getConnection(const rtl::OUString& user, const rtl::OUString& password) throw( SQLException, RuntimeException )
1144 {
1145     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getConnection" );
1146     return getConnection(user,password,sal_False);
1147 }
1148 // -----------------------------------------------------------------------------
1149 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const ::rtl::OUString& user, const ::rtl::OUString& password ) throw(SQLException, RuntimeException)
1150 {
1151     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getIsolatedConnection" );
1152     return getConnection(user,password,sal_True);
1153 }
1154 // -----------------------------------------------------------------------------
1155 Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler ) throw(SQLException, RuntimeException)
1156 {
1157     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getIsolatedConnectionWithCompletion" );
1158     return connectWithCompletion(_rxHandler,sal_True);
1159 }
1160 // -----------------------------------------------------------------------------
1161 Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,sal_Bool _bIsolated ) throw(SQLException, RuntimeException)
1162 {
1163     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::connectWithCompletion" );
1164     ModelMethodGuard aGuard( *this );
1165 
1166     if (!_rxHandler.is())
1167     {
1168         DBG_ERROR("ODatabaseSource::connectWithCompletion: invalid interaction handler!");
1169         return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
1170     }
1171 
1172     ::rtl::OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
1173     sal_Bool bNewPasswordGiven = sal_False;
1174 
1175     if (m_pImpl->m_bPasswordRequired && (0 == sPassword.getLength()))
1176     {   // we need a password, but don't have one yet.
1177         // -> ask the user
1178 
1179         // build an interaction request
1180         // two continuations (Ok and Cancel)
1181         OInteractionAbort* pAbort = new OInteractionAbort;
1182         OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation;
1183 
1184         // the name which should be referred in the login dialog
1185         ::rtl::OUString sServerName( m_pImpl->m_sName );
1186         INetURLObject aURLCheck( sServerName );
1187         if ( aURLCheck.GetProtocol() != INET_PROT_NOT_VALID )
1188             sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_UNAMBIGUOUS );
1189 
1190         // the request
1191         AuthenticationRequest aRequest;
1192         aRequest.ServerName = sServerName;
1193         aRequest.HasRealm = aRequest.HasAccount = sal_False;
1194         aRequest.HasUserName = aRequest.HasPassword = sal_True;
1195         aRequest.UserName = m_pImpl->m_sUser;
1196         aRequest.Password = m_pImpl->m_sFailedPassword.getLength() ? m_pImpl->m_sFailedPassword : m_pImpl->m_aPassword;
1197         OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest));
1198         Reference< XInteractionRequest > xRequest(pRequest);
1199         // some knittings
1200         pRequest->addContinuation(pAbort);
1201         pRequest->addContinuation(pAuthenticate);
1202 
1203         // handle the request
1204         try
1205         {
1206             MutexRelease aRelease( getMutex() );
1207                 // release the mutex when calling the handler, it may need to lock the SolarMutex
1208             _rxHandler->handle(xRequest);
1209         }
1210         catch(Exception&)
1211         {
1212             DBG_UNHANDLED_EXCEPTION();
1213         }
1214 
1215         if (!pAuthenticate->wasSelected())
1216             return Reference< XConnection >();
1217 
1218         // get the result
1219         sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
1220         sPassword = pAuthenticate->getPassword();
1221 
1222         if (pAuthenticate->getRememberPassword())
1223         {
1224             m_pImpl->m_aPassword = pAuthenticate->getPassword();
1225             bNewPasswordGiven = sal_True;
1226         }
1227         m_pImpl->m_sFailedPassword = ::rtl::OUString();
1228     }
1229 
1230     try
1231     {
1232         return getConnection(sUser, sPassword,_bIsolated);
1233     }
1234     catch(Exception&)
1235     {
1236         if (bNewPasswordGiven)
1237         {
1238             m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
1239             // assume that we had an authentication problem. Without this we may, after an unsucessful connect, while
1240             // the user gave us a password an the order to remember it, never allow an password input again (at least
1241             // not without restarting the session)
1242             m_pImpl->m_aPassword = ::rtl::OUString();
1243         }
1244         throw;
1245     }
1246 }
1247 
1248 // -----------------------------------------------------------------------------
1249 Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const rtl::OUString& user, const rtl::OUString& password)
1250 {
1251     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::buildIsolatedConnection" );
1252     Reference< XConnection > xConn;
1253     Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
1254     DBG_ASSERT( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
1255     // buildLowLevelConnection is expected to always succeed
1256     if ( xSdbcConn.is() )
1257     {
1258         // build a connection server and return it (no stubs)
1259         xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext.getLegacyServiceFactory());
1260     }
1261     return xConn;
1262 }
1263 //------------------------------------------------------------------------------
1264 Reference< XConnection > ODatabaseSource::getConnection(const rtl::OUString& user, const rtl::OUString& password,sal_Bool _bIsolated) throw( SQLException, RuntimeException )
1265 {
1266     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getConnection" );
1267     ModelMethodGuard aGuard( *this );
1268 
1269     Reference< XConnection > xConn;
1270     if ( _bIsolated )
1271     {
1272         xConn = buildIsolatedConnection(user,password);
1273     }
1274     else
1275     { // create a new proxy for the connection
1276         if ( !m_pImpl->m_xSharedConnectionManager.is() )
1277         {
1278             m_pImpl->m_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext.getLegacyServiceFactory() );
1279             m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
1280         }
1281         xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
1282             m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
1283     }
1284 
1285     if ( xConn.is() )
1286     {
1287         Reference< XComponent> xComp(xConn,UNO_QUERY);
1288         if ( xComp.is() )
1289             xComp->addEventListener( static_cast< XContainerListener* >( this ) );
1290         m_pImpl->m_aConnections.push_back(OWeakConnection(xConn));
1291     }
1292 
1293     return xConn;
1294 }
1295 
1296 //------------------------------------------------------------------------------
1297 Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks(  ) throw (RuntimeException)
1298 {
1299     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getBookmarks" );
1300     ModelMethodGuard aGuard( *this );
1301     return static_cast< XNameContainer* >(&m_aBookmarks);
1302 }
1303 
1304 //------------------------------------------------------------------------------
1305 Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( ) throw(RuntimeException)
1306 {
1307     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getQueryDefinitions" );
1308     ModelMethodGuard aGuard( *this );
1309 
1310     Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
1311     if ( !xContainer.is() )
1312     {
1313         Any aValue;
1314         ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xMy(*this);
1315         if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
1316         {
1317             ::rtl::OUString sSupportService;
1318             aValue >>= sSupportService;
1319             if ( sSupportService.getLength() )
1320             {
1321                 Sequence<Any> aArgs(1);
1322                 aArgs[0] <<= NamedValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSource")),makeAny(xMy));
1323                 xContainer.set(m_pImpl->m_aContext.createComponentWithArguments(sSupportService,aArgs),UNO_QUERY);
1324             }
1325         }
1326         if ( !xContainer.is() )
1327         {
1328             TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
1329             xContainer = new OCommandContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, sal_False );
1330         }
1331         m_pImpl->m_xCommandDefinitions = xContainer;
1332     }
1333     return xContainer;
1334 }
1335 //------------------------------------------------------------------------------
1336 // XTablesSupplier
1337 //------------------------------------------------------------------------------
1338 Reference< XNameAccess >  ODatabaseSource::getTables() throw( RuntimeException )
1339 {
1340     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getTables" );
1341     ModelMethodGuard aGuard( *this );
1342 
1343     Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
1344     if ( !xContainer.is() )
1345     {
1346         TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
1347         xContainer = new OCommandContainer( m_pImpl->m_aContext.getLegacyServiceFactory(), *this, rContainerData, sal_True );
1348         m_pImpl->m_xTableDefinitions = xContainer;
1349     }
1350     return xContainer;
1351 }
1352 // -----------------------------------------------------------------------------
1353 void SAL_CALL ODatabaseSource::flush(  ) throw (RuntimeException)
1354 {
1355     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::flush" );
1356     try
1357     {
1358         // SYNCHRONIZED ->
1359         {
1360             ModelMethodGuard aGuard( *this );
1361 
1362             typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
1363             SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
1364 
1365             if ( !xModel.is() )
1366                 xModel.reset( m_pImpl->createNewModel_deliverOwnership( false ), SharedModel::TakeOwnership );
1367 
1368             Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
1369             xStorable->store();
1370         }
1371         // <- SYNCHRONIZED
1372 
1373         css::lang::EventObject aFlushedEvent(*this);
1374         m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
1375     }
1376     catch( const Exception& )
1377     {
1378         DBG_UNHANDLED_EXCEPTION();
1379     }
1380 }
1381 
1382 // -----------------------------------------------------------------------------
1383 void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) throw (RuntimeException)
1384 {
1385     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::flushed" );
1386     ModelMethodGuard aGuard( *this );
1387 
1388     // Okay, this is some hack.
1389     //
1390     // In general, we have the problem that embedded databases write into their underlying storage, which
1391     // logically is one of our sub storage, and practically is a temporary file maintained by the
1392     // package implementation. As long as we did not commit this storage and our main storage,
1393     // the changes made by the embedded database engine are not really reflected in the database document
1394     // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
1395     // data, and then crashing: For a database application, you would expect that the data still is present
1396     // when you connect to the database next time.
1397     //
1398     // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
1399     // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
1400     // we cannot completely fix this. However, we can relax the problem by commiting more often - often
1401     // enough so that data loss is more seldom, and seldom enough so that there's no noticable performance
1402     // decrease.
1403     //
1404     // For this, we introduced a few places which XFlushable::flush their connections, and register as
1405     // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
1406     // Then, when the connection is flushed, we commit both the database storage and our main storage.
1407     //
1408     // #i55274# / 2005-09-30 / frank.schoenheit@sun.com
1409 
1410     OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
1411     sal_Bool bWasModified = m_pImpl->m_bModified;
1412     m_pImpl->commitEmbeddedStorage();
1413     m_pImpl->setModified( bWasModified );
1414 }
1415 
1416 // -----------------------------------------------------------------------------
1417 void SAL_CALL ODatabaseSource::addFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException)
1418 {
1419     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::addFlushListener" );
1420     m_aFlushListeners.addInterface(_xListener);
1421 }
1422 // -----------------------------------------------------------------------------
1423 void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< ::com::sun::star::util::XFlushListener >& _xListener ) throw (RuntimeException)
1424 {
1425     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::removeFlushListener" );
1426     m_aFlushListeners.removeInterface(_xListener);
1427 }
1428 // -----------------------------------------------------------------------------
1429 void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) throw (RuntimeException)
1430 {
1431     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementInserted" );
1432     ModelMethodGuard aGuard( *this );
1433     if ( m_pImpl.is() )
1434         m_pImpl->setModified(sal_True);
1435 }
1436 // -----------------------------------------------------------------------------
1437 void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) throw (RuntimeException)
1438 {
1439     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementRemoved" );
1440     ModelMethodGuard aGuard( *this );
1441     if ( m_pImpl.is() )
1442         m_pImpl->setModified(sal_True);
1443 }
1444 // -----------------------------------------------------------------------------
1445 void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) throw (RuntimeException)
1446 {
1447     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::elementReplaced" );
1448     ModelMethodGuard aGuard( *this );
1449     if ( m_pImpl.is() )
1450         m_pImpl->setModified(sal_True);
1451 }
1452 // -----------------------------------------------------------------------------
1453 // XDocumentDataSource
1454 Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() throw (RuntimeException)
1455 {
1456     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getDatabaseDocument" );
1457     ModelMethodGuard aGuard( *this );
1458 
1459     Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
1460     if ( !xModel.is() )
1461         xModel = m_pImpl->createNewModel_deliverOwnership( false );
1462 
1463     return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
1464 }
1465 // -----------------------------------------------------------------------------
1466 Reference< XInterface > ODatabaseSource::getThis() const
1467 {
1468     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dataaccess", "Ocke.Janssen@sun.com", "ODatabaseSource::getThis" );
1469     return *const_cast< ODatabaseSource* >( this );
1470 }
1471 // -----------------------------------------------------------------------------
1472 //........................................................................
1473 }   // namespace dbaccess
1474 //........................................................................
1475 
1476 
1477