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 "apitools.hxx"
32 #include "core_resource.hrc"
33 #include "core_resource.hxx"
34 #include "databasecontext.hxx"
35 #include "databasedocument.hxx"
36 #include "databaseregistrations.hxx"
37 #include "datasource.hxx"
38 #include "dbastrings.hrc"
39 #include "module_dba.hxx"
40 
41 /** === being UNO includes === **/
42 #include <com/sun/star/beans/NamedValue.hpp>
43 #include <com/sun/star/beans/PropertyAttribute.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/document/MacroExecMode.hpp>
46 #include <com/sun/star/document/XFilter.hpp>
47 #include <com/sun/star/document/XImporter.hpp>
48 #include <com/sun/star/frame/XDesktop.hpp>
49 #include <com/sun/star/frame/XModel.hpp>
50 #include <com/sun/star/frame/XModel2.hpp>
51 #include <com/sun/star/frame/XTerminateListener.hpp>
52 #include <com/sun/star/lang/DisposedException.hpp>
53 #include <com/sun/star/registry/InvalidRegistryException.hpp>
54 #include <com/sun/star/sdbc/XDataSource.hpp>
55 #include <com/sun/star/task/InteractionClassification.hpp>
56 #include <com/sun/star/ucb/InteractiveIOException.hpp>
57 #include <com/sun/star/ucb/IOErrorCode.hpp>
58 #include <com/sun/star/util/XCloseable.hpp>
59 /** === end UNO includes === **/
60 
61 #include <basic/basmgr.hxx>
62 #include <comphelper/enumhelper.hxx>
63 #include <comphelper/evtlistenerhlp.hxx>
64 #include <comphelper/namedvaluecollection.hxx>
65 #include <comphelper/processfactory.hxx>
66 #include <comphelper/sequence.hxx>
67 #include <cppuhelper/implbase1.hxx>
68 #include <cppuhelper/typeprovider.hxx>
69 #include <cppuhelper/exc_hlp.hxx>
70 #include <svl/filenotation.hxx>
71 #include <tools/debug.hxx>
72 #include <tools/diagnose_ex.h>
73 #include <tools/fsys.hxx>
74 #include <tools/urlobj.hxx>
75 #include <ucbhelper/content.hxx>
76 #include <unotools/confignode.hxx>
77 #include <unotools/pathoptions.hxx>
78 #include <unotools/sharedunocomponent.hxx>
79 #include <list>
80 #include <boost/bind.hpp>
81 
82 using namespace ::com::sun::star::sdbc;
83 using namespace ::com::sun::star::sdb;
84 using namespace ::com::sun::star::beans;
85 using namespace ::com::sun::star::uno;
86 using namespace ::com::sun::star::document;
87 using namespace ::com::sun::star::frame;
88 using namespace ::com::sun::star::lang;
89 using namespace ::com::sun::star::container;
90 using namespace ::com::sun::star::util;
91 using namespace ::com::sun::star::registry;
92 using namespace ::com::sun::star;
93 using namespace ::cppu;
94 using namespace ::osl;
95 using namespace ::utl;
96 
97 using ::com::sun::star::task::InteractionClassification_ERROR;
98 using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
99 using ::com::sun::star::ucb::InteractiveIOException;
100 using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
101 using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING_PATH;
102 
103 //==========================================================================
104 
105 extern "C" void SAL_CALL createRegistryInfo_ODatabaseContext()
106 {
107 	static ::dba::OLegacySingletonRegistration< ::dbaccess::ODatabaseContext > aODatabaseContext_AutoRegistration;
108 }
109 
110 //........................................................................
111 namespace dbaccess
112 {
113 //........................................................................
114 
115     // .............................................................................
116         typedef ::cppu::WeakImplHelper1 <   XTerminateListener
117                                         >   DatabaseDocumentLoader_Base;
118         class DatabaseDocumentLoader : public DatabaseDocumentLoader_Base
119         {
120         private:
121             Reference< XDesktop >               m_xDesktop;
122             ::std::list< const ODatabaseModelImpl* >  m_aDatabaseDocuments;
123 
124         public:
125             DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext);
126 
127             inline void append(const ODatabaseModelImpl& _rModelImpl )
128             {
129                 m_aDatabaseDocuments.push_back(&_rModelImpl);
130             }
131             inline void remove(const ODatabaseModelImpl& _rModelImpl) { m_aDatabaseDocuments.remove(&_rModelImpl); }
132 
133         private:
134             // XTerminateListener
135             virtual void SAL_CALL queryTermination( const lang::EventObject& Event ) throw (TerminationVetoException, RuntimeException);
136             virtual void SAL_CALL notifyTermination( const lang::EventObject& Event ) throw (RuntimeException);
137             // XEventListener
138             virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
139         };
140 
141         // .............................................................................
142         DatabaseDocumentLoader::DatabaseDocumentLoader( const comphelper::ComponentContext& _aContext )
143         {
144             acquire();
145             try
146             {
147                 m_xDesktop.set( _aContext.createComponent( (rtl::OUString)SERVICE_FRAME_DESKTOP ), UNO_QUERY_THROW );
148                 m_xDesktop->addTerminateListener( this );
149             }
150             catch( const Exception& )
151             {
152             	DBG_UNHANDLED_EXCEPTION();
153             }
154         }
155 
156         struct TerminateFunctor : ::std::unary_function<ODatabaseModelImpl* , void>
157         {
158             void operator()( const ODatabaseModelImpl* _pModelImpl ) const
159             {
160                 try
161                 {
162                     const Reference< XModel2> xModel( _pModelImpl ->getModel_noCreate(),UNO_QUERY_THROW );
163                     if ( !xModel->getControllers()->hasMoreElements() )
164                     {
165                         Reference<util::XCloseable> xCloseable(xModel,UNO_QUERY_THROW);
166                         xCloseable->close(sal_False);
167                     } // if ( !xModel->getControllers()->hasMoreElements() )
168                 }
169                 catch(const CloseVetoException&)
170                 {
171                     throw TerminationVetoException();
172                 }
173             }
174         };
175         // .............................................................................
176         void SAL_CALL DatabaseDocumentLoader::queryTermination( const lang::EventObject& /*Event*/ ) throw (TerminationVetoException, RuntimeException)
177         {
178             ::std::list< const ODatabaseModelImpl* > aCopy(m_aDatabaseDocuments);
179             ::std::for_each(aCopy.begin(),aCopy.end(),TerminateFunctor());
180         }
181 
182         // .............................................................................
183         void SAL_CALL DatabaseDocumentLoader::notifyTermination( const lang::EventObject& /*Event*/ ) throw (RuntimeException)
184         {
185         }
186         // .............................................................................
187         void SAL_CALL DatabaseDocumentLoader::disposing( const lang::EventObject& /*Source*/ ) throw (RuntimeException)
188         {
189         }
190 
191 //= ODatabaseContext
192 //==========================================================================
193 //--------------------------------------------------------------------------
194 ODatabaseContext::ODatabaseContext( const Reference< XComponentContext >& _rxContext )
195     :DatabaseAccessContext_Base(m_aMutex)
196     ,m_aContext( _rxContext )
197     ,m_aContainerListeners(m_aMutex)
198 {
199     m_pDatabaseDocumentLoader = new DatabaseDocumentLoader( m_aContext );
200     ::basic::BasicManagerRepository::registerCreationListener( *this );
201 
202     osl_incrementInterlockedCount( &m_refCount );
203     {
204         m_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW );
205         m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW );
206 
207         m_xDBRegistrationAggregate->setDelegator( *this );
208     }
209     osl_decrementInterlockedCount( &m_refCount );
210 }
211 
212 //--------------------------------------------------------------------------
213 ODatabaseContext::~ODatabaseContext()
214 {
215     ::basic::BasicManagerRepository::revokeCreationListener( *this );
216     if ( m_pDatabaseDocumentLoader )
217         m_pDatabaseDocumentLoader->release();
218 
219     m_xDBRegistrationAggregate->setDelegator( NULL );
220     m_xDBRegistrationAggregate.clear();
221     m_xDatabaseRegistrations.clear();
222 }
223 
224 // Helper
225 //------------------------------------------------------------------------------
226 rtl::OUString ODatabaseContext::getImplementationName_static() throw( RuntimeException )
227 
228 {
229 	return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.dba.ODatabaseContext"));
230 }
231 
232 //------------------------------------------------------------------------------
233 Reference< XInterface > ODatabaseContext::Create(const Reference< XComponentContext >& _rxContext)
234 {
235 	return *( new ODatabaseContext( _rxContext ) );
236 }
237 
238 //------------------------------------------------------------------------------
239 Sequence< rtl::OUString > ODatabaseContext::getSupportedServiceNames_static(void) throw( RuntimeException )
240 {
241 	Sequence< ::rtl::OUString > aSNS( 1 );
242 	aSNS[0] = SERVICE_SDB_DATABASECONTEXT;
243 	return aSNS;
244 }
245 
246 // XServiceInfo
247 //------------------------------------------------------------------------------
248 rtl::OUString ODatabaseContext::getImplementationName(  ) throw(RuntimeException)
249 {
250 	return getImplementationName_static();
251 }
252 
253 //------------------------------------------------------------------------------
254 sal_Bool ODatabaseContext::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
255 {
256 	return ::comphelper::findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0;
257 }
258 
259 //------------------------------------------------------------------------------
260 Sequence< ::rtl::OUString > ODatabaseContext::getSupportedServiceNames(  ) throw (RuntimeException)
261 {
262 	return getSupportedServiceNames_static();
263 }
264 
265 //--------------------------------------------------------------------------
266 Reference< XInterface > ODatabaseContext::impl_createNewDataSource()
267 {
268 	::rtl::Reference<ODatabaseModelImpl> pImpl( new ODatabaseModelImpl( m_aContext.getLegacyServiceFactory(), *this ) );
269     Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() );
270 
271     return xDataSource.get();
272 }
273 
274 //--------------------------------------------------------------------------
275 Reference< XInterface > SAL_CALL ODatabaseContext::createInstance(  ) throw (Exception, RuntimeException)
276 {
277     // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew
278     // has been called at the DatabaseDocument).
279     return impl_createNewDataSource();
280 }
281 
282 //--------------------------------------------------------------------------
283 Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException)
284 {
285     ::comphelper::NamedValueCollection aArgs( _rArguments );
286     ::rtl::OUString sURL = aArgs.getOrDefault( (::rtl::OUString)INFO_POOLURL, ::rtl::OUString() );
287 
288 	Reference< XInterface > xDataSource;
289     if ( sURL.getLength() )
290         xDataSource = getObject( sURL );
291 
292     if ( !xDataSource.is() )
293 		xDataSource = impl_createNewDataSource();
294 
295 	return xDataSource;
296 }
297 // DatabaseAccessContext_Base
298 //------------------------------------------------------------------------------
299 void ODatabaseContext::disposing()
300 {
301 	// notify our listener
302 	com::sun::star::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this));
303 	m_aContainerListeners.disposeAndClear(aDisposeEvent);
304 
305 	// dispose the data sources
306 	ObjectCache::iterator aEnd = m_aDatabaseObjects.end();
307 	for	(	ObjectCache::iterator	aIter = m_aDatabaseObjects.begin();
308 			aIter != aEnd;
309 			++aIter
310 		)
311 	{
312 		aIter->second->dispose();
313 	}
314 	m_aDatabaseObjects.clear();
315 }
316 
317 // XNamingService
318 //------------------------------------------------------------------------------
319 Reference< XInterface >  ODatabaseContext::getRegisteredObject(const rtl::OUString& _rName) throw( Exception, RuntimeException )
320 {
321 	MutexGuard aGuard(m_aMutex);
322 	::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
323 
324     ::rtl::OUString sURL( getDatabaseLocation( _rName ) );
325 
326 	if ( !sURL.getLength() )
327         // there is a registration for this name, but no URL
328 		throw IllegalArgumentException();
329 
330 	// check if URL is already loaded
331 	Reference< XInterface > xExistent = getObject( sURL );
332 	if ( xExistent.is() )
333 		return xExistent;
334 
335 	return loadObjectFromURL( _rName, sURL );
336 }
337 // -----------------------------------------------------------------------------
338 Reference< XInterface > ODatabaseContext::loadObjectFromURL(const ::rtl::OUString& _rName,const ::rtl::OUString& _sURL)
339 {
340     INetURLObject aURL( _sURL );
341     if ( aURL.GetProtocol() == INET_PROT_NOT_VALID )
342         throw NoSuchElementException( _rName, *this );
343 
344 	try
345 	{
346 		::ucbhelper::Content aContent( _sURL, NULL );
347 		if ( !aContent.isDocument() )
348 			throw InteractiveIOException(
349                 _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE
350             );
351 	}
352 	catch ( const InteractiveIOException& e )
353 	{
354         if  (   ( e.Code == IOErrorCode_NO_FILE )
355             ||  ( e.Code == IOErrorCode_NOT_EXISTING )
356             ||  ( e.Code == IOErrorCode_NOT_EXISTING_PATH )
357             )
358         {
359             // #i40463# #i39187#
360             String sErrorMessage( DBACORE_RESSTRING( RID_STR_FILE_DOES_NOT_EXIST ) );
361             ::svt::OFileNotation aTransformer( _sURL );
362 		    sErrorMessage.SearchAndReplaceAscii( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
363 
364             SQLException aError;
365             aError.Message = sErrorMessage;
366 
367             throw WrappedTargetException( _sURL, *this, makeAny( aError ) );
368         }
369 		throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
370 	}
371 	catch( const Exception& )
372 	{
373         throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
374 	}
375 
376     OSL_ENSURE( m_aDatabaseObjects.find( _sURL ) == m_aDatabaseObjects.end(),
377         "ODatabaseContext::loadObjectFromURL: not intended for already-cached objects!" );
378 
379     ::rtl::Reference< ODatabaseModelImpl > pModelImpl;
380     {
381 		pModelImpl.set( new ODatabaseModelImpl( _rName, m_aContext.getLegacyServiceFactory(), *this ) );
382 
383 	    Reference< XModel > xModel( pModelImpl->createNewModel_deliverOwnership( false ), UNO_SET_THROW );
384         Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
385 
386         ::comphelper::NamedValueCollection aArgs;
387         aArgs.put( "URL", _sURL );
388         aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
389         aArgs.put( "InteractionHandler", m_aContext.createComponent( "com.sun.star.task.InteractionHandler" ) );
390 
391         Sequence< PropertyValue > aResource( aArgs.getPropertyValues() );
392         xLoad->load( aResource );
393         xModel->attachResource( _sURL, aResource );
394 
395         ::utl::CloseableComponent aEnsureClose( xModel );
396     }
397 
398     setTransientProperties( _sURL, *pModelImpl );
399 
400     return pModelImpl->getOrCreateDataSource().get();
401 }
402 // -----------------------------------------------------------------------------
403 void ODatabaseContext::appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
404 {
405     m_pDatabaseDocumentLoader->append(_rDataSourceModel);
406 }
407 // -----------------------------------------------------------------------------
408 void ODatabaseContext::removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
409 {
410     m_pDatabaseDocumentLoader->remove(_rDataSourceModel);
411 }
412 // -----------------------------------------------------------------------------
413 void ODatabaseContext::setTransientProperties(const ::rtl::OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel )
414 {
415 	if ( m_aDatasourceProperties.end() == m_aDatasourceProperties.find(_sURL) )
416         return;
417     try
418     {
419         ::rtl::OUString sAuthFailedPassword;
420 	    Reference< XPropertySet > xDSProps( _rDataSourceModel.getOrCreateDataSource(), UNO_QUERY_THROW );
421 		const Sequence< PropertyValue >& rSessionPersistentProps = m_aDatasourceProperties[_sURL];
422 		const PropertyValue* pProp = rSessionPersistentProps.getConstArray();
423 		const PropertyValue* pPropsEnd = rSessionPersistentProps.getConstArray() + rSessionPersistentProps.getLength();
424         for ( ; pProp != pPropsEnd; ++pProp )
425         {
426             if ( pProp->Name.equalsAscii( "AuthFailedPassword" ) )
427             {
428                 OSL_VERIFY( pProp->Value >>= sAuthFailedPassword );
429             }
430             else
431             {
432 				xDSProps->setPropertyValue( pProp->Name, pProp->Value );
433             }
434 		}
435 
436         _rDataSourceModel.m_sFailedPassword = sAuthFailedPassword;
437     }
438     catch( const Exception& )
439     {
440     	DBG_UNHANDLED_EXCEPTION();
441     }
442 }
443 
444 //------------------------------------------------------------------------------
445 void ODatabaseContext::registerObject(const rtl::OUString& _rName, const Reference< XInterface > & _rxObject) throw( Exception, RuntimeException )
446 {
447 	MutexGuard aGuard(m_aMutex);
448 	::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
449 
450 	if ( !_rName.getLength() )
451 		throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
452 
453     Reference< XDocumentDataSource > xDocDataSource( _rxObject, UNO_QUERY );
454 	Reference< XModel > xModel( xDocDataSource.is() ? xDocDataSource->getDatabaseDocument() : Reference< XOfficeDatabaseDocument >(), UNO_QUERY );
455     if ( !xModel.is() )
456 		throw IllegalArgumentException( ::rtl::OUString(), *this, 2 );
457 
458 	::rtl::OUString sURL = xModel->getURL();
459 	if ( !sURL.getLength() )
460 		throw IllegalArgumentException( DBACORE_RESSTRING( RID_STR_DATASOURCE_NOT_STORED ), *this, 2 );
461 
462     registerDatabaseLocation( _rName, sURL );
463 
464     ODatabaseSource::setName( xDocDataSource, _rName, ODatabaseSource::DBContextAccess() );
465 
466 	// notify our container listeners
467 	ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rName), makeAny(_rxObject), Any());
468     m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
469 }
470 
471 //------------------------------------------------------------------------------
472 void ODatabaseContext::storeTransientProperties( ODatabaseModelImpl& _rModelImpl)
473 {
474     Reference< XPropertySet > xSource( _rModelImpl.getOrCreateDataSource(), UNO_QUERY );
475     ::comphelper::NamedValueCollection aRememberProps;
476 
477 	try
478 	{
479 		// get the info about the properties, check which ones are transient and not readonly
480 		Reference< XPropertySetInfo > xSetInfo;
481 		if (xSource.is())
482 			xSetInfo = xSource->getPropertySetInfo();
483 		Sequence< Property > aProperties;
484 		if (xSetInfo.is())
485 			aProperties = xSetInfo->getProperties();
486 
487 		if (aProperties.getLength())
488 		{
489 			const Property* pProperties = aProperties.getConstArray();
490 			for ( sal_Int32 i=0; i<aProperties.getLength(); ++i, ++pProperties )
491 			{
492 				if	(	( ( pProperties->Attributes & PropertyAttribute::TRANSIENT) != 0 )
493 					&&	( ( pProperties->Attributes & PropertyAttribute::READONLY) == 0 )
494 					)
495 				{
496 					// found such a property
497                     aRememberProps.put( pProperties->Name, xSource->getPropertyValue( pProperties->Name ) );
498 				}
499 			}
500 		}
501 	}
502 	catch ( const Exception& )
503 	{
504         DBG_UNHANDLED_EXCEPTION();
505 	}
506 
507     // additionally, remember the "failed password", which is not available as property
508     // #i86178# / 2008-02-19 / frank.schoenheit@sun.com
509     aRememberProps.put( "AuthFailedPassword", _rModelImpl.m_sFailedPassword );
510 
511     ::rtl::OUString sDocumentURL( _rModelImpl.getURL() );
512     if ( m_aDatabaseObjects.find( sDocumentURL ) != m_aDatabaseObjects.end() )
513     {
514 	    m_aDatasourceProperties[ sDocumentURL ] = aRememberProps.getPropertyValues();
515     }
516     else if ( m_aDatabaseObjects.find( _rModelImpl.m_sName ) != m_aDatabaseObjects.end() )
517     {
518         OSL_ENSURE( false, "ODatabaseContext::storeTransientProperties: a database document register by name? This shouldn't happen anymore!" );
519             // all the code should have been changed so that registration is by URL only
520 	    m_aDatasourceProperties[ _rModelImpl.m_sName ] = aRememberProps.getPropertyValues();
521     }
522     else
523     {
524         OSL_ENSURE( ( sDocumentURL.getLength() == 0 ) && ( _rModelImpl.m_sName.getLength() == 0 ),
525             "ODatabaseContext::storeTransientProperties: a non-empty data source which I do not know?!" );
526     }
527 }
528 
529 //------------------------------------------------------------------------------
530 void SAL_CALL ODatabaseContext::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
531 {
532 	m_aContainerListeners.addInterface(_rxListener);
533 }
534 
535 //------------------------------------------------------------------------------
536 void SAL_CALL ODatabaseContext::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
537 {
538 	m_aContainerListeners.removeInterface(_rxListener);
539 }
540 
541 //------------------------------------------------------------------------------
542 void ODatabaseContext::revokeObject(const rtl::OUString& _rName) throw( Exception, RuntimeException )
543 {
544 	ClearableMutexGuard aGuard(m_aMutex);
545     ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
546 
547     ::rtl::OUString sURL = getDatabaseLocation( _rName );
548 
549     revokeDatabaseLocation( _rName );
550         // will throw if something goes wrong
551 
552     if ( m_aDatabaseObjects.find( _rName ) != m_aDatabaseObjects.end() )
553     {
554         m_aDatasourceProperties[ sURL ] = m_aDatasourceProperties[ _rName ];
555     }
556 
557 	// check if URL is already loaded
558 	ObjectCacheIterator aExistent = m_aDatabaseObjects.find( sURL );
559 	if ( aExistent != m_aDatabaseObjects.end() )
560 		m_aDatabaseObjects.erase( aExistent );
561 
562 	// notify our container listeners
563 	ContainerEvent aEvent( *this, makeAny( _rName ), Any(), Any() );
564     aGuard.clear();
565     m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
566 }
567 
568 //------------------------------------------------------------------------------
569 ::sal_Bool SAL_CALL ODatabaseContext::hasRegisteredDatabase( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, RuntimeException)
570 {
571     return m_xDatabaseRegistrations->hasRegisteredDatabase( _Name );
572 }
573 
574 //------------------------------------------------------------------------------
575 Sequence< ::rtl::OUString > SAL_CALL ODatabaseContext::getRegistrationNames() throw (RuntimeException)
576 {
577     return m_xDatabaseRegistrations->getRegistrationNames();
578 }
579 
580 //------------------------------------------------------------------------------
581 ::rtl::OUString SAL_CALL ODatabaseContext::getDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
582 {
583     return m_xDatabaseRegistrations->getDatabaseLocation( _Name );
584 }
585 
586 //------------------------------------------------------------------------------
587 void SAL_CALL ODatabaseContext::registerDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _Location ) throw (IllegalArgumentException, ElementExistException, RuntimeException)
588 {
589     m_xDatabaseRegistrations->registerDatabaseLocation( _Name, _Location );
590 }
591 
592 //------------------------------------------------------------------------------
593 void SAL_CALL ODatabaseContext::revokeDatabaseLocation( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException)
594 {
595     m_xDatabaseRegistrations->revokeDatabaseLocation( _Name );
596 }
597 
598 //------------------------------------------------------------------------------
599 void SAL_CALL ODatabaseContext::changeDatabaseLocation( const ::rtl::OUString& _Name, const ::rtl::OUString& _NewLocation ) throw (IllegalArgumentException, NoSuchElementException, IllegalAccessException, RuntimeException)
600 {
601     m_xDatabaseRegistrations->changeDatabaseLocation( _Name, _NewLocation );
602 }
603 
604 //------------------------------------------------------------------------------
605 ::sal_Bool SAL_CALL ODatabaseContext::isDatabaseRegistrationReadOnly( const ::rtl::OUString& _Name ) throw (IllegalArgumentException, NoSuchElementException, RuntimeException)
606 {
607     return m_xDatabaseRegistrations->isDatabaseRegistrationReadOnly( _Name );
608 }
609 
610 //------------------------------------------------------------------------------
611 void SAL_CALL ODatabaseContext::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException)
612 {
613     m_xDatabaseRegistrations->addDatabaseRegistrationsListener( _Listener );
614 }
615 
616 //------------------------------------------------------------------------------
617 void SAL_CALL ODatabaseContext::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& _Listener ) throw (RuntimeException)
618 {
619     m_xDatabaseRegistrations->removeDatabaseRegistrationsListener( _Listener );
620 }
621 
622 // ::com::sun::star::container::XElementAccess
623 //------------------------------------------------------------------------------
624 Type ODatabaseContext::getElementType(  ) throw(RuntimeException)
625 {
626 	return::getCppuType(static_cast<Reference<XDataSource>*>(NULL));
627 }
628 
629 //------------------------------------------------------------------------------
630 sal_Bool ODatabaseContext::hasElements(void) throw( RuntimeException )
631 {
632 	MutexGuard aGuard(m_aMutex);
633 	::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
634 
635 	return 0 != getElementNames().getLength();
636 }
637 
638 // ::com::sun::star::container::XEnumerationAccess
639 //------------------------------------------------------------------------------
640 Reference< ::com::sun::star::container::XEnumeration >  ODatabaseContext::createEnumeration(void) throw( RuntimeException )
641 {
642 	MutexGuard aGuard(m_aMutex);
643 	return new ::comphelper::OEnumerationByName(static_cast<XNameAccess*>(this));
644 }
645 
646 // ::com::sun::star::container::XNameAccess
647 //------------------------------------------------------------------------------
648 Any ODatabaseContext::getByName(const rtl::OUString& _rName) throw( NoSuchElementException,
649 														  WrappedTargetException, RuntimeException )
650 {
651 	MutexGuard aGuard(m_aMutex);
652 	::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
653 	if ( !_rName.getLength() )
654 		throw NoSuchElementException(_rName, *this);
655 
656 	try
657 	{
658 		Reference< XInterface > xExistent = getObject( _rName );
659 		if ( xExistent.is() )
660 			return makeAny( xExistent );
661 
662         // see whether this is an registered name
663         ::rtl::OUString sURL;
664         if ( hasRegisteredDatabase( _rName ) )
665         {
666             sURL = getDatabaseLocation( _rName );
667             // is the object cached under its URL?
668 	        xExistent = getObject( sURL );
669         }
670         else
671             // interpret the name as URL
672             sURL = _rName;
673 
674         if ( !xExistent.is() )
675 		    // try to load this as URL
676             xExistent = loadObjectFromURL( _rName, sURL );
677 		return makeAny( xExistent );
678 	}
679 	catch (NoSuchElementException&)
680 	{	// let these exceptions through
681 		throw;
682 	}
683 	catch (WrappedTargetException&)
684 	{	// let these exceptions through
685 		throw;
686 	}
687 	catch (RuntimeException&)
688 	{	// let these exceptions through
689 		throw;
690 	}
691 	catch (Exception& e)
692 	{	// exceptions other than the speciafied ones -> wrap
693         Any aError = ::cppu::getCaughtException();
694 		throw WrappedTargetException(_rName, *this, aError );
695 	}
696 }
697 
698 //------------------------------------------------------------------------------
699 Sequence< rtl::OUString > ODatabaseContext::getElementNames(void) throw( RuntimeException )
700 {
701 	MutexGuard aGuard(m_aMutex);
702     ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
703 
704     return getRegistrationNames();
705 }
706 
707 //------------------------------------------------------------------------------
708 sal_Bool ODatabaseContext::hasByName(const rtl::OUString& _rName) throw( RuntimeException )
709 {
710 	MutexGuard aGuard(m_aMutex);
711 	::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
712 
713     return hasRegisteredDatabase( _rName );
714 }
715 
716 // -----------------------------------------------------------------------------
717 Reference< XInterface > ODatabaseContext::getObject( const ::rtl::OUString& _rURL )
718 {
719 	ObjectCacheIterator aFind = m_aDatabaseObjects.find( _rURL );
720 	Reference< XInterface > xExistent;
721 	if ( aFind != m_aDatabaseObjects.end() )
722 		xExistent = aFind->second->getOrCreateDataSource();
723 	return xExistent;
724 }
725 // -----------------------------------------------------------------------------
726 void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl )
727 {
728     ::rtl::OUString sURL( _rModelImpl.getURL() );
729 #if OSL_DEBUG_LEVEL > 1
730     OSL_TRACE( "DatabaseContext: registering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() );
731 #endif
732 	if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() )
733 	{
734 		m_aDatabaseObjects[ sURL ] = &_rModelImpl;
735         setTransientProperties( sURL, _rModelImpl );
736 	}
737     else
738         OSL_ENSURE( false, "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" );
739 }
740 // -----------------------------------------------------------------------------
741 void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl )
742 {
743     ::rtl::OUString sURL( _rModelImpl.getURL() );
744 #if OSL_DEBUG_LEVEL > 1
745     OSL_TRACE( "DatabaseContext: deregistering %s", ::rtl::OUStringToOString( sURL, RTL_TEXTENCODING_UTF8 ).getStr() );
746 #endif
747 	m_aDatabaseObjects.erase( sURL );
748 }
749 // -----------------------------------------------------------------------------
750 void ODatabaseContext::databaseDocumentURLChange( const ::rtl::OUString& _rOldURL, const ::rtl::OUString& _rNewURL )
751 {
752 #if OSL_DEBUG_LEVEL > 1
753     OSL_TRACE( "DatabaseContext: changing registration from %s to %s",
754         ::rtl::OUStringToOString( _rOldURL, RTL_TEXTENCODING_UTF8 ).getStr(),
755         ::rtl::OUStringToOString( _rNewURL, RTL_TEXTENCODING_UTF8 ).getStr() );
756 #endif
757     ObjectCache::iterator oldPos = m_aDatabaseObjects.find( _rOldURL );
758     ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" );
759     ObjectCache::iterator newPos = m_aDatabaseObjects.find( _rNewURL );
760     ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" );
761 
762     m_aDatabaseObjects[ _rNewURL ] = oldPos->second;
763     m_aDatabaseObjects.erase( oldPos );
764 }
765 // -----------------------------------------------------------------------------
766 sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId ) throw(RuntimeException)
767 {
768 	if (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
769 		return reinterpret_cast<sal_Int64>(this);
770 
771 	return 0;
772 }
773 // -----------------------------------------------------------------------------
774 Sequence< sal_Int8 > ODatabaseContext::getUnoTunnelImplementationId()
775 {
776 	static ::cppu::OImplementationId * pId = 0;
777 	if (! pId)
778 	{
779 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
780 		if (! pId)
781 		{
782 			static ::cppu::OImplementationId aId;
783 			pId = &aId;
784 		}
785 	}
786 	return pId->getImplementationId();
787 }
788 
789 // -----------------------------------------------------------------------------
790 void ODatabaseContext::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager )
791 {
792     // if it's a database document ...
793     Reference< XOfficeDatabaseDocument > xDatabaseDocument( _rxForDocument, UNO_QUERY );
794     // ... or a sub document of a database document ...
795     if ( !xDatabaseDocument.is() )
796     {
797         Reference< XChild > xDocAsChild( _rxForDocument, UNO_QUERY );
798         if ( xDocAsChild.is() )
799             xDatabaseDocument.set( xDocAsChild->getParent(), UNO_QUERY );
800     }
801 
802     // ... whose BasicManager has just been created, then add the global DatabaseDocument variable to its scope.
803     if ( xDatabaseDocument.is() )
804         _rBasicManager.SetGlobalUNOConstant( "ThisDatabaseDocument", makeAny( xDatabaseDocument ) );
805 }
806 
807 //........................................................................
808 }	// namespace dbaccess
809 //........................................................................
810