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