1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: datasourcehandling.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
33 #include "datasourcehandling.hxx"
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/sdb/SQLContext.hpp>
38 #include <com/sun/star/task/XInteractionHandler.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/frame/XStorable.hpp>
41 #include <com/sun/star/uno/XNamingService.hpp>
42 #include <com/sun/star/lang/XComponent.hpp>
43 #include <com/sun/star/sdbc/XConnection.hpp>
44 #include <com/sun/star/sdb/XCompletedConnection.hpp>
45 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
46 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
47 #include <tools/debug.hxx>
48 #include <comphelper/interaction.hxx>
49 #include <vcl/stdtext.hxx>
50 #ifndef EXTENSIONS_ABPRESID_HRC
51 #include "abpresid.hrc"
53 #include "componentmodule.hxx"
54 #include "abptypes.hxx"
55 #include <unotools/confignode.hxx>
56 #include <unotools/sharedunocomponent.hxx>
58 //.........................................................................
61 //.........................................................................
63 using namespace ::utl
;
64 using namespace ::comphelper
;
65 using namespace ::com::sun::star::uno
;
66 using namespace ::com::sun::star::lang
;
67 using namespace ::com::sun::star::sdb
;
68 using namespace ::com::sun::star::sdbc
;
69 using namespace ::com::sun::star::task
;
70 using namespace ::com::sun::star::beans
;
71 using namespace ::com::sun::star::sdbcx
;
72 using namespace ::com::sun::star::container
;
73 using namespace ::com::sun::star::frame
;
75 //=====================================================================
76 struct PackageAccessControl
{ };
78 //=====================================================================
79 //--------------------------------------------------------------------
80 static const ::rtl::OUString
& getDbRegisteredNamesNodeName()
82 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("org.openoffice.Office.DataAccess/RegisteredNames");
86 //--------------------------------------------------------------------
87 static const ::rtl::OUString
& getDbNameNodeName()
89 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("Name");
93 //--------------------------------------------------------------------
94 static const ::rtl::OUString
& getDbLocationNodeName()
96 static ::rtl::OUString s_sNodeName
= ::rtl::OUString::createFromAscii("Location");
99 //---------------------------------------------------------------------
100 static Reference
< XNameAccess
> lcl_getDataSourceContext( const Reference
< XMultiServiceFactory
>& _rxORB
) SAL_THROW (( Exception
))
102 Reference
< XNameAccess
> xContext( _rxORB
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.sdb.DatabaseContext" ) ), UNO_QUERY
);
103 DBG_ASSERT(xContext
.is(), "lcl_getDataSourceContext: could not access the data source context!");
107 //---------------------------------------------------------------------
108 /// creates a new data source and inserts it into the context
109 static void lcl_implCreateAndInsert(
110 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _rName
,
111 Reference
< XPropertySet
>& /* [out] */ _rxNewDataSource
) SAL_THROW (( ::com::sun::star::uno::Exception
))
113 //.............................................................
114 // get the data source context
115 Reference
< XNameAccess
> xContext
= lcl_getDataSourceContext( _rxORB
);
117 DBG_ASSERT( !xContext
->hasByName( _rName
), "lcl_implCreateAndInsert: name already used!" );
120 //.............................................................
121 // create a new data source
122 Reference
< XSingleServiceFactory
> xFactory( xContext
, UNO_QUERY
);
123 Reference
< XPropertySet
> xNewDataSource
;
125 xNewDataSource
= Reference
< XPropertySet
>( xFactory
->createInstance(), UNO_QUERY
);
126 DBG_ASSERT( xNewDataSource
.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
128 //.............................................................
129 // insert the data source into the context
130 Reference
< XNamingService
> xDynamicContext( xContext
, UNO_QUERY
);
131 DBG_ASSERT( xDynamicContext
.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
132 if (xDynamicContext
.is())
134 // xDynamicContext->registerObject( _rName, xNewDataSource );
135 _rxNewDataSource
= xNewDataSource
;
139 //---------------------------------------------------------------------
140 /// creates and inserts a data source, and sets it's URL property to the string given
141 static ODataSource
lcl_implCreateAndSetURL(
142 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _rName
,
143 const sal_Char
* _pInitialAsciiURL
) SAL_THROW (( ))
145 ODataSource
aReturn( _rxORB
);
148 // create the new data source
149 Reference
< XPropertySet
> xNewDataSource
;
150 lcl_implCreateAndInsert( _rxORB
, _rName
, xNewDataSource
);
152 //.............................................................
153 // set the URL property
154 if (xNewDataSource
.is())
156 xNewDataSource
->setPropertyValue(
157 ::rtl::OUString::createFromAscii( "URL" ),
158 makeAny( ::rtl::OUString::createFromAscii( _pInitialAsciiURL
) )
162 aReturn
.setDataSource( xNewDataSource
, _rName
,PackageAccessControl() );
164 catch(const Exception
&)
166 DBG_ERROR( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
171 //---------------------------------------------------------------------
172 void lcl_registerDataSource(
173 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _sName
,
174 const ::rtl::OUString
& _sURL
) SAL_THROW (( ::com::sun::star::uno::Exception
))
176 // the config node where all pooling relevant info are stored under
177 OConfigurationTreeRoot aDbRegisteredNamesRoot
= OConfigurationTreeRoot::createWithServiceFactory(
178 _rxORB
, getDbRegisteredNamesNodeName(), -1, OConfigurationTreeRoot::CM_UPDATABLE
);
180 if (!aDbRegisteredNamesRoot
.isValid())
181 // already asserted by the OConfigurationTreeRoot
184 OSL_ENSURE(_sName
.getLength(),"No Name given!");
185 OSL_ENSURE(_sURL
.getLength(),"No URL given!");
187 OConfigurationNode aThisDriverSettings
;
188 if ( aDbRegisteredNamesRoot
.hasByName(_sName
) )
189 aThisDriverSettings
= aDbRegisteredNamesRoot
.openNode(_sName
);
191 aThisDriverSettings
= aDbRegisteredNamesRoot
.createNode(_sName
);
194 aThisDriverSettings
.setNodeValue(getDbNameNodeName(), makeAny(_sName
));
195 aThisDriverSettings
.setNodeValue(getDbLocationNodeName(), makeAny(_sURL
));
197 aDbRegisteredNamesRoot
.commit();
200 //=====================================================================
201 //= ODataSourceContextImpl
202 //=====================================================================
203 struct ODataSourceContextImpl
205 Reference
< XMultiServiceFactory
> xORB
;
206 Reference
< XNameAccess
> xContext
; /// the UNO data source context
207 StringBag aDataSourceNames
; /// for quicker name checks (without the UNO overhead)
209 ODataSourceContextImpl( const Reference
< XMultiServiceFactory
>& _rxORB
) : xORB( _rxORB
) { }
210 ODataSourceContextImpl( const ODataSourceContextImpl
& _rSource
)
211 :xORB ( _rSource
.xORB
)
212 ,xContext ( _rSource
.xContext
)
217 //=====================================================================
218 //= ODataSourceContext
219 //=====================================================================
220 //---------------------------------------------------------------------
221 ODataSourceContext::ODataSourceContext(const Reference
< XMultiServiceFactory
>& _rxORB
)
222 :m_pImpl( new ODataSourceContextImpl( _rxORB
) )
226 // create the UNO context
227 m_pImpl
->xContext
= lcl_getDataSourceContext( _rxORB
);
229 if (m_pImpl
->xContext
.is())
231 // collect the data source names
232 Sequence
< ::rtl::OUString
> aDSNames
= m_pImpl
->xContext
->getElementNames();
233 const ::rtl::OUString
* pDSNames
= aDSNames
.getConstArray();
234 const ::rtl::OUString
* pDSNamesEnd
= pDSNames
+ aDSNames
.getLength();
236 for ( ;pDSNames
!= pDSNamesEnd
; ++pDSNames
)
237 m_pImpl
->aDataSourceNames
.insert( *pDSNames
);
240 catch( const Exception
& )
242 DBG_ERROR( "ODataSourceContext::ODataSourceContext: caught an exception!" );
246 //---------------------------------------------------------------------
247 ::rtl::OUString
& ODataSourceContext::disambiguate(::rtl::OUString
& _rDataSourceName
)
249 ::rtl::OUString
sCheck( _rDataSourceName
);
250 ConstStringBagIterator aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
252 sal_Int32 nPostFix
= 1;
253 while ( ( m_pImpl
->aDataSourceNames
.end() != aPos
) && ( nPostFix
< 65535 ) )
254 { // there already is a data source with this name
255 sCheck
= _rDataSourceName
;
256 sCheck
+= ::rtl::OUString::valueOf( nPostFix
++ );
258 aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
261 _rDataSourceName
= sCheck
;
262 return _rDataSourceName
;
265 //---------------------------------------------------------------------
266 void ODataSourceContext::getDataSourceNames( StringBag
& _rNames
) const SAL_THROW (( ))
268 _rNames
= m_pImpl
->aDataSourceNames
;
271 //---------------------------------------------------------------------
272 ODataSource
ODataSourceContext::createNewLDAP( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
274 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:ldap:" );
277 //---------------------------------------------------------------------
278 ODataSource
ODataSourceContext::createNewMORK( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
280 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:mozilla" );
283 //---------------------------------------------------------------------
284 ODataSource
ODataSourceContext::createNewThunderbird( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
286 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:thunderbird" );
289 //---------------------------------------------------------------------
290 ODataSource
ODataSourceContext::createNewEvolutionLdap( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
292 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:ldap" );
294 //---------------------------------------------------------------------
295 ODataSource
ODataSourceContext::createNewEvolutionGroupwise( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
297 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:groupwise" );
299 //---------------------------------------------------------------------
300 ODataSource
ODataSourceContext::createNewEvolution( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
302 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:local" );
305 //---------------------------------------------------------------------
306 ODataSource
ODataSourceContext::createNewKab( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
308 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:kab" );
311 //---------------------------------------------------------------------
312 ODataSource
ODataSourceContext::createNewMacab( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
314 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:macab" );
317 //---------------------------------------------------------------------
318 ODataSource
ODataSourceContext::createNewOutlook( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
320 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlook" );
323 //---------------------------------------------------------------------
324 ODataSource
ODataSourceContext::createNewOE( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
326 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlookexp" );
329 //---------------------------------------------------------------------
330 ODataSource
ODataSourceContext::createNewDBase( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
332 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:dbase:" );
335 //=====================================================================
337 //=====================================================================
338 struct ODataSourceImpl
341 Reference
< XMultiServiceFactory
> xORB
; /// the service factory
342 Reference
< XPropertySet
> xDataSource
; /// the UNO data source
343 ::utl::SharedUNOComponent
< XConnection
>
345 StringBag aTables
; // the cached table names
346 ::rtl::OUString sName
;
347 sal_Bool bTablesUpToDate
; // table name cache up-to-date?
349 ODataSourceImpl( const Reference
< XMultiServiceFactory
>& _rxORB
)
351 ,bTablesUpToDate( sal_False
)
355 ODataSourceImpl( const ODataSourceImpl
& _rSource
);
358 //---------------------------------------------------------------------
359 ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl
& _rSource
)
360 :xORB( _rSource
.xORB
)
361 ,xDataSource( _rSource
.xDataSource
)
362 ,xConnection( _rSource
.xConnection
)
363 ,aTables( _rSource
.aTables
)
364 ,sName( _rSource
.sName
)
365 ,bTablesUpToDate( _rSource
.bTablesUpToDate
)
369 //=====================================================================
371 //=====================================================================
372 //---------------------------------------------------------------------
373 ODataSource::ODataSource( const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _rName
)
374 :m_pImpl(new ODataSourceImpl(_rxORB
))
378 // get the data source context
379 Reference
< XNameAccess
> xContext
= lcl_getDataSourceContext( m_pImpl
->xORB
);
381 // retrieve the UNO data source
383 xContext
->getByName( _rName
) >>= m_pImpl
->xDataSource
;
385 catch(const Exception
&)
387 DBG_ERROR("ODataSource::ODataSource: could not access the requested data source (caught an exception)!");
391 //---------------------------------------------------------------------
392 ODataSource::ODataSource( const ODataSource
& _rSource
)
398 //---------------------------------------------------------------------
399 ODataSource
& ODataSource::operator=( const ODataSource
& _rSource
)
402 m_pImpl
= new ODataSourceImpl( *_rSource
.m_pImpl
);
407 //---------------------------------------------------------------------
408 ODataSource::ODataSource( const Reference
< XMultiServiceFactory
>& _rxORB
)
409 :m_pImpl(new ODataSourceImpl(_rxORB
))
413 //---------------------------------------------------------------------
414 ODataSource::~ODataSource( )
419 //---------------------------------------------------------------------
420 void ODataSource::store() SAL_THROW (( ))
427 Reference
< XDocumentDataSource
> xDocAccess( m_pImpl
->xDataSource
, UNO_QUERY
);
428 Reference
< XStorable
> xStorable
;
429 if ( xDocAccess
.is() )
430 xStorable
= xStorable
.query( xDocAccess
->getDatabaseDocument() );
431 OSL_ENSURE( xStorable
.is(),"DataSource is no XStorable!" );
432 if ( xStorable
.is() )
433 xStorable
->storeAsURL(m_pImpl
->sName
,Sequence
<PropertyValue
>());
435 catch(const Exception
&)
437 DBG_ERROR( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
440 //---------------------------------------------------------------------
441 void ODataSource::registerDataSource( const ::rtl::OUString
& _sRegisteredDataSourceName
) SAL_THROW (( ))
449 // invalidate ourself
450 lcl_registerDataSource(m_pImpl
->xORB
,_sRegisteredDataSourceName
,m_pImpl
->sName
);
452 catch(const Exception
&)
454 DBG_ERROR( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
458 //---------------------------------------------------------------------
459 void ODataSource::setDataSource( const Reference
< XPropertySet
>& _rxDS
,const ::rtl::OUString
& _sName
, PackageAccessControl
)
461 if (m_pImpl
->xDataSource
.get() == _rxDS
.get())
468 m_pImpl
->sName
= _sName
;
469 m_pImpl
->xDataSource
= _rxDS
;
472 //---------------------------------------------------------------------
473 void ODataSource::remove() SAL_THROW (( ))
481 // invalidate ourself
482 m_pImpl
->xDataSource
.clear();
484 catch(const Exception
&)
486 DBG_ERROR( "ODataSource::remove: caught an exception while creating the data source!" );
490 //---------------------------------------------------------------------
491 sal_Bool
ODataSource::rename( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
497 m_pImpl
->sName
= _rName
;
501 //---------------------------------------------------------------------
502 ::rtl::OUString
ODataSource::getName() const SAL_THROW (( ))
505 return ::rtl::OUString();
506 return m_pImpl
->sName
;
509 //---------------------------------------------------------------------
510 bool ODataSource::hasTable( const ::rtl::OUString
& _rTableName
) const
512 if ( !isConnected() )
515 const StringBag
& aTables( getTableNames() );
516 return aTables
.find( _rTableName
) != aTables
.end();
519 //---------------------------------------------------------------------
520 const StringBag
& ODataSource::getTableNames() const SAL_THROW (( ))
522 m_pImpl
->aTables
.clear();
523 if ( !isConnected() )
525 DBG_ERROR( "ODataSource::getTableNames: not connected!" );
531 // get the tables container from the connection
532 Reference
< XTablesSupplier
> xSuppTables( m_pImpl
->xConnection
.getTyped(), UNO_QUERY
);
533 Reference
< XNameAccess
> xTables
;
534 if ( xSuppTables
.is( ) )
535 xTables
= xSuppTables
->getTables();
536 DBG_ASSERT( xTables
.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
539 Sequence
< ::rtl::OUString
> aTableNames
;
541 aTableNames
= xTables
->getElementNames( );
544 const ::rtl::OUString
* pTableNames
= aTableNames
.getConstArray();
545 const ::rtl::OUString
* pTableNamesEnd
= pTableNames
+ aTableNames
.getLength();
546 for (;pTableNames
< pTableNamesEnd
; ++pTableNames
)
547 m_pImpl
->aTables
.insert( *pTableNames
);
549 catch(const Exception
&)
554 // now the table cache is up-to-date
555 m_pImpl
->bTablesUpToDate
= sal_True
;
556 return m_pImpl
->aTables
;
559 //---------------------------------------------------------------------
560 sal_Bool
ODataSource::connect( Window
* _pMessageParent
) SAL_THROW (( ))
562 if ( isConnected( ) )
566 // ................................................................
567 // create the interaction handler (needed for authentication and error handling)
568 static ::rtl::OUString s_sInteractionHandlerServiceName
= ::rtl::OUString::createFromAscii("com.sun.star.sdb.InteractionHandler");
569 Reference
< XInteractionHandler
> xInteractions
;
572 xInteractions
= Reference
< XInteractionHandler
>(
573 m_pImpl
->xORB
->createInstance( s_sInteractionHandlerServiceName
),
577 catch(const Exception
&)
581 // ................................................................
582 // failure to create the interaction handler is a serious issue ...
583 if (!xInteractions
.is())
585 if ( _pMessageParent
)
586 ShowServiceNotAvailableError( _pMessageParent
, s_sInteractionHandlerServiceName
, sal_True
);
590 // ................................................................
591 // open the connection
593 Reference
< XConnection
> xConnection
;
596 Reference
< XCompletedConnection
> xComplConn( m_pImpl
->xDataSource
, UNO_QUERY
);
597 DBG_ASSERT( xComplConn
.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
598 if ( xComplConn
.is() )
599 xConnection
= xComplConn
->connectWithCompletion( xInteractions
);
601 catch( const SQLContext
& e
) { aError
<<= e
; }
602 catch( const SQLWarning
& e
) { aError
<<= e
; }
603 catch( const SQLException
& e
) { aError
<<= e
; }
604 catch( const Exception
& )
606 DBG_ERROR( "ODataSource::connect: caught a generic exception!" );
609 // ................................................................
611 if ( aError
.hasValue() && _pMessageParent
)
615 SQLException aException
;
616 aError
>>= aException
;
617 if ( !aException
.Message
.getLength() )
619 // prepend some context info
620 SQLContext aDetailedError
;
621 aDetailedError
.Message
= String( ModuleRes( RID_STR_NOCONNECTION
) );
622 aDetailedError
.Details
= String( ModuleRes( RID_STR_PLEASECHECKSETTINGS
) );
623 aDetailedError
.NextException
= aError
;
624 // handle (aka display) the new context info
625 xInteractions
->handle( new OInteractionRequest( makeAny( aDetailedError
) ) );
629 // handle (aka display) the original error
630 xInteractions
->handle( new OInteractionRequest( makeAny( aException
) ) );
633 catch( const Exception
& )
635 DBG_ERROR( "ODataSource::connect: caught an exception while trying to display the error!" );
639 if ( !xConnection
.is() )
642 // ................................................................
644 m_pImpl
->xConnection
.reset( xConnection
);
645 m_pImpl
->aTables
.clear();
646 m_pImpl
->bTablesUpToDate
= sal_False
;
651 //---------------------------------------------------------------------
652 void ODataSource::disconnect( ) SAL_THROW (( ))
654 m_pImpl
->xConnection
.clear();
655 m_pImpl
->aTables
.clear();
656 m_pImpl
->bTablesUpToDate
= sal_False
;
659 //---------------------------------------------------------------------
660 sal_Bool
ODataSource::isConnected( ) const SAL_THROW (( ))
662 return m_pImpl
->xConnection
.is();
665 //---------------------------------------------------------------------
666 sal_Bool
ODataSource::isValid() const SAL_THROW (( ))
668 return m_pImpl
&& m_pImpl
->xDataSource
.is();
670 //---------------------------------------------------------------------
671 Reference
< XPropertySet
> ODataSource::getDataSource() const SAL_THROW (( ))
673 return m_pImpl
? m_pImpl
->xDataSource
: Reference
< XPropertySet
>();
676 //.........................................................................
678 //.........................................................................