1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
31 #include "abpresid.hrc"
32 #include "abptypes.hxx"
33 #include "componentmodule.hxx"
34 #include "datasourcehandling.hxx"
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/container/XNameAccess.hpp>
38 #include <com/sun/star/frame/XStorable.hpp>
39 #include <com/sun/star/lang/XComponent.hpp>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
42 #include <com/sun/star/sdb/SQLContext.hpp>
43 #include <com/sun/star/sdb/XCompletedConnection.hpp>
44 #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
45 #include <com/sun/star/sdb/XDocumentDataSource.hpp>
46 #include <com/sun/star/sdbc/XConnection.hpp>
47 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
48 #include <com/sun/star/task/XInteractionHandler.hpp>
49 #include <com/sun/star/uno/XNamingService.hpp>
51 #include <comphelper/interaction.hxx>
52 #include <comphelper/componentcontext.hxx>
53 #include <tools/debug.hxx>
54 #include <tools/diagnose_ex.h>
55 #include <unotools/confignode.hxx>
56 #include <unotools/sharedunocomponent.hxx>
57 #include <vcl/stdtext.hxx>
59 //.........................................................................
62 //.........................................................................
64 using namespace ::utl
;
65 using namespace ::comphelper
;
66 using namespace ::com::sun::star::uno
;
67 using namespace ::com::sun::star::lang
;
68 using namespace ::com::sun::star::sdb
;
69 using namespace ::com::sun::star::sdbc
;
70 using namespace ::com::sun::star::task
;
71 using namespace ::com::sun::star::beans
;
72 using namespace ::com::sun::star::sdbcx
;
73 using namespace ::com::sun::star::container
;
74 using namespace ::com::sun::star::frame
;
76 //=====================================================================
77 struct PackageAccessControl
{ };
79 //=====================================================================
80 //---------------------------------------------------------------------
81 static Reference
< XNameAccess
> lcl_getDataSourceContext( const Reference
< XMultiServiceFactory
>& _rxORB
) SAL_THROW (( Exception
))
83 Reference
< XNameAccess
> xContext( _rxORB
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.sdb.DatabaseContext" ) ), UNO_QUERY
);
84 DBG_ASSERT(xContext
.is(), "lcl_getDataSourceContext: could not access the data source context!");
88 //---------------------------------------------------------------------
89 /// creates a new data source and inserts it into the context
90 static void lcl_implCreateAndInsert(
91 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _rName
,
92 Reference
< XPropertySet
>& /* [out] */ _rxNewDataSource
) SAL_THROW (( ::com::sun::star::uno::Exception
))
94 //.............................................................
95 // get the data source context
96 Reference
< XNameAccess
> xContext
= lcl_getDataSourceContext( _rxORB
);
98 DBG_ASSERT( !xContext
->hasByName( _rName
), "lcl_implCreateAndInsert: name already used!" );
101 //.............................................................
102 // create a new data source
103 Reference
< XSingleServiceFactory
> xFactory( xContext
, UNO_QUERY
);
104 Reference
< XPropertySet
> xNewDataSource
;
106 xNewDataSource
= Reference
< XPropertySet
>( xFactory
->createInstance(), UNO_QUERY
);
107 DBG_ASSERT( xNewDataSource
.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
109 //.............................................................
110 // insert the data source into the context
111 Reference
< XNamingService
> xDynamicContext( xContext
, UNO_QUERY
);
112 DBG_ASSERT( xDynamicContext
.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
113 if (xDynamicContext
.is())
115 // xDynamicContext->registerObject( _rName, xNewDataSource );
116 _rxNewDataSource
= xNewDataSource
;
120 //---------------------------------------------------------------------
121 /// creates and inserts a data source, and sets it's URL property to the string given
122 static ODataSource
lcl_implCreateAndSetURL(
123 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _rName
,
124 const sal_Char
* _pInitialAsciiURL
) SAL_THROW (( ))
126 ODataSource
aReturn( _rxORB
);
129 // create the new data source
130 Reference
< XPropertySet
> xNewDataSource
;
131 lcl_implCreateAndInsert( _rxORB
, _rName
, xNewDataSource
);
133 //.............................................................
134 // set the URL property
135 if (xNewDataSource
.is())
137 xNewDataSource
->setPropertyValue(
138 ::rtl::OUString::createFromAscii( "URL" ),
139 makeAny( ::rtl::OUString::createFromAscii( _pInitialAsciiURL
) )
143 aReturn
.setDataSource( xNewDataSource
, _rName
,PackageAccessControl() );
145 catch(const Exception
&)
147 DBG_ERROR( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
152 //---------------------------------------------------------------------
153 void lcl_registerDataSource(
154 const Reference
< XMultiServiceFactory
>& _rxORB
, const ::rtl::OUString
& _sName
,
155 const ::rtl::OUString
& _sURL
) SAL_THROW (( ::com::sun::star::uno::Exception
))
157 OSL_ENSURE( _sName
.getLength(), "lcl_registerDataSource: invalid name!" );
158 OSL_ENSURE( _sURL
.getLength(), "lcl_registerDataSource: invalid URL!" );
162 ::comphelper::ComponentContext
aContext( _rxORB
);
163 Reference
< XDatabaseRegistrations
> xRegistrations(
164 aContext
.createComponent( "com.sun.star.sdb.DatabaseContext" ), UNO_QUERY_THROW
);
166 if ( xRegistrations
->hasRegisteredDatabase( _sName
) )
167 xRegistrations
->changeDatabaseLocation( _sName
, _sURL
);
169 xRegistrations
->registerDatabaseLocation( _sName
, _sURL
);
171 catch( const Exception
& )
173 DBG_UNHANDLED_EXCEPTION();
177 //=====================================================================
178 //= ODataSourceContextImpl
179 //=====================================================================
180 struct ODataSourceContextImpl
182 Reference
< XMultiServiceFactory
> xORB
;
183 Reference
< XNameAccess
> xContext
; /// the UNO data source context
184 StringBag aDataSourceNames
; /// for quicker name checks (without the UNO overhead)
186 ODataSourceContextImpl( const Reference
< XMultiServiceFactory
>& _rxORB
) : xORB( _rxORB
) { }
187 ODataSourceContextImpl( const ODataSourceContextImpl
& _rSource
)
188 :xORB ( _rSource
.xORB
)
189 ,xContext ( _rSource
.xContext
)
194 //=====================================================================
195 //= ODataSourceContext
196 //=====================================================================
197 //---------------------------------------------------------------------
198 ODataSourceContext::ODataSourceContext(const Reference
< XMultiServiceFactory
>& _rxORB
)
199 :m_pImpl( new ODataSourceContextImpl( _rxORB
) )
203 // create the UNO context
204 m_pImpl
->xContext
= lcl_getDataSourceContext( _rxORB
);
206 if (m_pImpl
->xContext
.is())
208 // collect the data source names
209 Sequence
< ::rtl::OUString
> aDSNames
= m_pImpl
->xContext
->getElementNames();
210 const ::rtl::OUString
* pDSNames
= aDSNames
.getConstArray();
211 const ::rtl::OUString
* pDSNamesEnd
= pDSNames
+ aDSNames
.getLength();
213 for ( ;pDSNames
!= pDSNamesEnd
; ++pDSNames
)
214 m_pImpl
->aDataSourceNames
.insert( *pDSNames
);
217 catch( const Exception
& )
219 DBG_ERROR( "ODataSourceContext::ODataSourceContext: caught an exception!" );
223 //---------------------------------------------------------------------
224 ::rtl::OUString
& ODataSourceContext::disambiguate(::rtl::OUString
& _rDataSourceName
)
226 ::rtl::OUString
sCheck( _rDataSourceName
);
227 ConstStringBagIterator aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
229 sal_Int32 nPostFix
= 1;
230 while ( ( m_pImpl
->aDataSourceNames
.end() != aPos
) && ( nPostFix
< 65535 ) )
231 { // there already is a data source with this name
232 sCheck
= _rDataSourceName
;
233 sCheck
+= ::rtl::OUString::valueOf( nPostFix
++ );
235 aPos
= m_pImpl
->aDataSourceNames
.find( sCheck
);
238 _rDataSourceName
= sCheck
;
239 return _rDataSourceName
;
242 //---------------------------------------------------------------------
243 void ODataSourceContext::getDataSourceNames( StringBag
& _rNames
) const SAL_THROW (( ))
245 _rNames
= m_pImpl
->aDataSourceNames
;
248 //---------------------------------------------------------------------
249 ODataSource
ODataSourceContext::createNewLDAP( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
251 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:ldap:" );
254 //---------------------------------------------------------------------
255 ODataSource
ODataSourceContext::createNewMORK( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
257 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:mozilla" );
260 //---------------------------------------------------------------------
261 ODataSource
ODataSourceContext::createNewThunderbird( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
263 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:thunderbird" );
266 //---------------------------------------------------------------------
267 ODataSource
ODataSourceContext::createNewEvolutionLdap( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
269 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:ldap" );
271 //---------------------------------------------------------------------
272 ODataSource
ODataSourceContext::createNewEvolutionGroupwise( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
274 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:groupwise" );
276 //---------------------------------------------------------------------
277 ODataSource
ODataSourceContext::createNewEvolution( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
279 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:evolution:local" );
282 //---------------------------------------------------------------------
283 ODataSource
ODataSourceContext::createNewKab( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
285 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:kab" );
288 //---------------------------------------------------------------------
289 ODataSource
ODataSourceContext::createNewMacab( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
291 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:macab" );
294 //---------------------------------------------------------------------
295 ODataSource
ODataSourceContext::createNewOutlook( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
297 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlook" );
300 //---------------------------------------------------------------------
301 ODataSource
ODataSourceContext::createNewOE( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
303 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:address:outlookexp" );
306 //---------------------------------------------------------------------
307 ODataSource
ODataSourceContext::createNewDBase( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
309 return lcl_implCreateAndSetURL( m_pImpl
->xORB
, _rName
, "sdbc:dbase:" );
312 //=====================================================================
314 //=====================================================================
315 struct ODataSourceImpl
318 Reference
< XMultiServiceFactory
> xORB
; /// the service factory
319 Reference
< XPropertySet
> xDataSource
; /// the UNO data source
320 ::utl::SharedUNOComponent
< XConnection
>
322 StringBag aTables
; // the cached table names
323 ::rtl::OUString sName
;
324 sal_Bool bTablesUpToDate
; // table name cache up-to-date?
326 ODataSourceImpl( const Reference
< XMultiServiceFactory
>& _rxORB
)
328 ,bTablesUpToDate( sal_False
)
332 ODataSourceImpl( const ODataSourceImpl
& _rSource
);
335 //---------------------------------------------------------------------
336 ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl
& _rSource
)
337 :xORB( _rSource
.xORB
)
338 ,xDataSource( _rSource
.xDataSource
)
339 ,xConnection( _rSource
.xConnection
)
340 ,aTables( _rSource
.aTables
)
341 ,sName( _rSource
.sName
)
342 ,bTablesUpToDate( _rSource
.bTablesUpToDate
)
346 //=====================================================================
348 //=====================================================================
349 //---------------------------------------------------------------------
350 ODataSource::ODataSource( const ODataSource
& _rSource
)
356 //---------------------------------------------------------------------
357 ODataSource
& ODataSource::operator=( const ODataSource
& _rSource
)
360 m_pImpl
= new ODataSourceImpl( *_rSource
.m_pImpl
);
365 //---------------------------------------------------------------------
366 ODataSource::ODataSource( const Reference
< XMultiServiceFactory
>& _rxORB
)
367 :m_pImpl(new ODataSourceImpl(_rxORB
))
371 //---------------------------------------------------------------------
372 ODataSource::~ODataSource( )
377 //---------------------------------------------------------------------
378 void ODataSource::store() SAL_THROW (( ))
385 Reference
< XDocumentDataSource
> xDocAccess( m_pImpl
->xDataSource
, UNO_QUERY
);
386 Reference
< XStorable
> xStorable
;
387 if ( xDocAccess
.is() )
388 xStorable
= xStorable
.query( xDocAccess
->getDatabaseDocument() );
389 OSL_ENSURE( xStorable
.is(),"DataSource is no XStorable!" );
390 if ( xStorable
.is() )
391 xStorable
->storeAsURL(m_pImpl
->sName
,Sequence
<PropertyValue
>());
393 catch(const Exception
&)
395 DBG_ERROR( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
398 //---------------------------------------------------------------------
399 void ODataSource::registerDataSource( const ::rtl::OUString
& _sRegisteredDataSourceName
) SAL_THROW (( ))
407 // invalidate ourself
408 lcl_registerDataSource(m_pImpl
->xORB
,_sRegisteredDataSourceName
,m_pImpl
->sName
);
410 catch(const Exception
&)
412 DBG_ERROR( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
416 //---------------------------------------------------------------------
417 void ODataSource::setDataSource( const Reference
< XPropertySet
>& _rxDS
,const ::rtl::OUString
& _sName
, PackageAccessControl
)
419 if (m_pImpl
->xDataSource
.get() == _rxDS
.get())
426 m_pImpl
->sName
= _sName
;
427 m_pImpl
->xDataSource
= _rxDS
;
430 //---------------------------------------------------------------------
431 void ODataSource::remove() SAL_THROW (( ))
439 // invalidate ourself
440 m_pImpl
->xDataSource
.clear();
442 catch(const Exception
&)
444 DBG_ERROR( "ODataSource::remove: caught an exception while creating the data source!" );
448 //---------------------------------------------------------------------
449 sal_Bool
ODataSource::rename( const ::rtl::OUString
& _rName
) SAL_THROW (( ))
455 m_pImpl
->sName
= _rName
;
459 //---------------------------------------------------------------------
460 ::rtl::OUString
ODataSource::getName() const SAL_THROW (( ))
463 return ::rtl::OUString();
464 return m_pImpl
->sName
;
467 //---------------------------------------------------------------------
468 bool ODataSource::hasTable( const ::rtl::OUString
& _rTableName
) const
470 if ( !isConnected() )
473 const StringBag
& aTables( getTableNames() );
474 return aTables
.find( _rTableName
) != aTables
.end();
477 //---------------------------------------------------------------------
478 const StringBag
& ODataSource::getTableNames() const SAL_THROW (( ))
480 m_pImpl
->aTables
.clear();
481 if ( !isConnected() )
483 DBG_ERROR( "ODataSource::getTableNames: not connected!" );
489 // get the tables container from the connection
490 Reference
< XTablesSupplier
> xSuppTables( m_pImpl
->xConnection
.getTyped(), UNO_QUERY
);
491 Reference
< XNameAccess
> xTables
;
492 if ( xSuppTables
.is( ) )
493 xTables
= xSuppTables
->getTables();
494 DBG_ASSERT( xTables
.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
497 Sequence
< ::rtl::OUString
> aTableNames
;
499 aTableNames
= xTables
->getElementNames( );
502 const ::rtl::OUString
* pTableNames
= aTableNames
.getConstArray();
503 const ::rtl::OUString
* pTableNamesEnd
= pTableNames
+ aTableNames
.getLength();
504 for (;pTableNames
< pTableNamesEnd
; ++pTableNames
)
505 m_pImpl
->aTables
.insert( *pTableNames
);
507 catch(const Exception
&)
512 // now the table cache is up-to-date
513 m_pImpl
->bTablesUpToDate
= sal_True
;
514 return m_pImpl
->aTables
;
517 //---------------------------------------------------------------------
518 sal_Bool
ODataSource::connect( Window
* _pMessageParent
) SAL_THROW (( ))
520 if ( isConnected( ) )
524 // ................................................................
525 // create the interaction handler (needed for authentication and error handling)
526 static ::rtl::OUString s_sInteractionHandlerServiceName
= ::rtl::OUString::createFromAscii("com.sun.star.task.InteractionHandler");
527 Reference
< XInteractionHandler
> xInteractions
;
530 xInteractions
= Reference
< XInteractionHandler
>(
531 m_pImpl
->xORB
->createInstance( s_sInteractionHandlerServiceName
),
535 catch(const Exception
&)
539 // ................................................................
540 // failure to create the interaction handler is a serious issue ...
541 if (!xInteractions
.is())
543 if ( _pMessageParent
)
544 ShowServiceNotAvailableError( _pMessageParent
, s_sInteractionHandlerServiceName
, sal_True
);
548 // ................................................................
549 // open the connection
551 Reference
< XConnection
> xConnection
;
554 Reference
< XCompletedConnection
> xComplConn( m_pImpl
->xDataSource
, UNO_QUERY
);
555 DBG_ASSERT( xComplConn
.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
556 if ( xComplConn
.is() )
557 xConnection
= xComplConn
->connectWithCompletion( xInteractions
);
559 catch( const SQLContext
& e
) { aError
<<= e
; }
560 catch( const SQLWarning
& e
) { aError
<<= e
; }
561 catch( const SQLException
& e
) { aError
<<= e
; }
562 catch( const Exception
& )
564 DBG_ERROR( "ODataSource::connect: caught a generic exception!" );
567 // ................................................................
569 if ( aError
.hasValue() && _pMessageParent
)
573 SQLException aException
;
574 aError
>>= aException
;
575 if ( !aException
.Message
.getLength() )
577 // prepend some context info
578 SQLContext aDetailedError
;
579 aDetailedError
.Message
= String( ModuleRes( RID_STR_NOCONNECTION
) );
580 aDetailedError
.Details
= String( ModuleRes( RID_STR_PLEASECHECKSETTINGS
) );
581 aDetailedError
.NextException
= aError
;
582 // handle (aka display) the new context info
583 xInteractions
->handle( new OInteractionRequest( makeAny( aDetailedError
) ) );
587 // handle (aka display) the original error
588 xInteractions
->handle( new OInteractionRequest( makeAny( aException
) ) );
591 catch( const Exception
& )
593 DBG_ERROR( "ODataSource::connect: caught an exception while trying to display the error!" );
597 if ( !xConnection
.is() )
600 // ................................................................
602 m_pImpl
->xConnection
.reset( xConnection
);
603 m_pImpl
->aTables
.clear();
604 m_pImpl
->bTablesUpToDate
= sal_False
;
609 //---------------------------------------------------------------------
610 void ODataSource::disconnect( ) SAL_THROW (( ))
612 m_pImpl
->xConnection
.clear();
613 m_pImpl
->aTables
.clear();
614 m_pImpl
->bTablesUpToDate
= sal_False
;
617 //---------------------------------------------------------------------
618 sal_Bool
ODataSource::isConnected( ) const SAL_THROW (( ))
620 return m_pImpl
->xConnection
.is();
623 //---------------------------------------------------------------------
624 sal_Bool
ODataSource::isValid() const SAL_THROW (( ))
626 return m_pImpl
&& m_pImpl
->xDataSource
.is();
628 //---------------------------------------------------------------------
629 Reference
< XPropertySet
> ODataSource::getDataSource() const SAL_THROW (( ))
631 return m_pImpl
? m_pImpl
->xDataSource
: Reference
< XPropertySet
>();
634 //.........................................................................
636 //.........................................................................