Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "abpresid.hrc"
22 : #include "abptypes.hxx"
23 : #include "componentmodule.hxx"
24 : #include "datasourcehandling.hxx"
25 :
26 : #include <boost/noncopyable.hpp>
27 : #include <com/sun/star/beans/XPropertySet.hpp>
28 : #include <com/sun/star/container/XNameAccess.hpp>
29 : #include <com/sun/star/frame/XStorable.hpp>
30 : #include <com/sun/star/lang/XComponent.hpp>
31 : #include <com/sun/star/lang/XSingleServiceFactory.hpp>
32 : #include <com/sun/star/sdb/DatabaseContext.hpp>
33 : #include <com/sun/star/sdb/SQLContext.hpp>
34 : #include <com/sun/star/sdb/XCompletedConnection.hpp>
35 : #include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
36 : #include <com/sun/star/sdb/XDocumentDataSource.hpp>
37 : #include <com/sun/star/sdbc/XConnection.hpp>
38 : #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
39 : #include <com/sun/star/task/InteractionHandler.hpp>
40 : #include <com/sun/star/uno/XNamingService.hpp>
41 :
42 : #include <comphelper/interaction.hxx>
43 : #include <comphelper/processfactory.hxx>
44 : #include <tools/debug.hxx>
45 : #include <tools/diagnose_ex.h>
46 : #include <unotools/confignode.hxx>
47 : #include <unotools/sharedunocomponent.hxx>
48 : #include <vcl/stdtext.hxx>
49 :
50 :
51 : namespace abp
52 : {
53 :
54 :
55 : using namespace ::utl;
56 : using namespace ::comphelper;
57 : using namespace ::com::sun::star::uno;
58 : using namespace ::com::sun::star::lang;
59 : using namespace ::com::sun::star::sdb;
60 : using namespace ::com::sun::star::sdbc;
61 : using namespace ::com::sun::star::task;
62 : using namespace ::com::sun::star::beans;
63 : using namespace ::com::sun::star::sdbcx;
64 : using namespace ::com::sun::star::container;
65 : using namespace ::com::sun::star::frame;
66 :
67 :
68 : struct PackageAccessControl { };
69 :
70 :
71 :
72 0 : static Reference< XDatabaseContext > lcl_getDataSourceContext( const Reference< XComponentContext >& _rxContext )
73 : {
74 0 : Reference<XDatabaseContext> xContext = DatabaseContext::create(_rxContext);
75 0 : return xContext;
76 : }
77 :
78 :
79 : /// creates a new data source and inserts it into the context
80 0 : static void lcl_implCreateAndInsert(
81 : const Reference< XComponentContext >& _rxContext, const OUString& _rName,
82 : Reference< XPropertySet >& /* [out] */ _rxNewDataSource )
83 : {
84 :
85 : // get the data source context
86 0 : Reference< XDatabaseContext > xContext = lcl_getDataSourceContext( _rxContext );
87 :
88 : DBG_ASSERT( !xContext->hasByName( _rName ), "lcl_implCreateAndInsert: name already used!" );
89 : (void)_rName;
90 :
91 :
92 : // create a new data source
93 0 : Reference< XPropertySet > xNewDataSource;
94 0 : if (xContext.is())
95 0 : xNewDataSource = Reference< XPropertySet >( xContext->createInstance(), UNO_QUERY );
96 : DBG_ASSERT( xNewDataSource.is(), "lcl_implCreateAndInsert: could not create a new data source!" );
97 :
98 :
99 : // insert the data source into the context
100 : DBG_ASSERT( xContext.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" );
101 0 : if (xContext.is())
102 : {
103 : // xDynamicContext->registerObject( _rName, xNewDataSource );
104 0 : _rxNewDataSource = xNewDataSource;
105 0 : }
106 0 : }
107 :
108 :
109 : /// creates and inserts a data source, and sets its URL property to the string given
110 0 : static ODataSource lcl_implCreateAndSetURL(
111 : const Reference< XComponentContext >& _rxORB, const OUString& _rName,
112 : const sal_Char* _pInitialAsciiURL )
113 : {
114 0 : ODataSource aReturn( _rxORB );
115 : try
116 : {
117 : // create the new data source
118 0 : Reference< XPropertySet > xNewDataSource;
119 0 : lcl_implCreateAndInsert( _rxORB, _rName, xNewDataSource );
120 :
121 :
122 : // set the URL property
123 0 : if (xNewDataSource.is())
124 : {
125 0 : xNewDataSource->setPropertyValue(
126 : OUString( "URL" ),
127 : makeAny( OUString::createFromAscii( _pInitialAsciiURL ) )
128 0 : );
129 : }
130 :
131 0 : aReturn.setDataSource( xNewDataSource, _rName,PackageAccessControl() );
132 : }
133 0 : catch(const Exception&)
134 : {
135 : OSL_FAIL( "lcl_implCreateAndSetURL: caught an exception while creating the data source!" );
136 : }
137 :
138 0 : return aReturn;
139 : }
140 :
141 0 : void lcl_registerDataSource(
142 : const Reference< XComponentContext >& _rxORB, const OUString& _sName,
143 : const OUString& _sURL )
144 : {
145 : OSL_ENSURE( !_sName.isEmpty(), "lcl_registerDataSource: invalid name!" );
146 : OSL_ENSURE( !_sURL.isEmpty(), "lcl_registerDataSource: invalid URL!" );
147 : try
148 : {
149 0 : Reference< XDatabaseContext > xRegistrations( DatabaseContext::create(_rxORB) );
150 0 : if ( xRegistrations->hasRegisteredDatabase( _sName ) )
151 0 : xRegistrations->changeDatabaseLocation( _sName, _sURL );
152 : else
153 0 : xRegistrations->registerDatabaseLocation( _sName, _sURL );
154 : }
155 0 : catch( const Exception& )
156 : {
157 : DBG_UNHANDLED_EXCEPTION();
158 : }
159 0 : }
160 :
161 :
162 : //= ODataSourceContextImpl
163 :
164 0 : struct ODataSourceContextImpl: private boost::noncopyable
165 : {
166 : Reference< XComponentContext > xORB;
167 : Reference< XNameAccess > xContext; /// the UNO data source context
168 : StringBag aDataSourceNames; /// for quicker name checks (without the UNO overhead)
169 :
170 0 : ODataSourceContextImpl( const Reference< XComponentContext >& _rxORB ) : xORB( _rxORB ) { }
171 : };
172 :
173 :
174 : //= ODataSourceContext
175 :
176 :
177 0 : ODataSourceContext::ODataSourceContext(const Reference< XComponentContext >& _rxORB)
178 0 : :m_pImpl( new ODataSourceContextImpl( _rxORB ) )
179 : {
180 : try
181 : {
182 : // create the UNO context
183 0 : m_pImpl->xContext = Reference<XNameAccess>(
184 : lcl_getDataSourceContext( _rxORB ),
185 0 : UNO_QUERY_THROW);
186 :
187 0 : if (m_pImpl->xContext.is())
188 : {
189 : // collect the data source names
190 0 : Sequence< OUString > aDSNames = m_pImpl->xContext->getElementNames();
191 0 : const OUString* pDSNames = aDSNames.getConstArray();
192 0 : const OUString* pDSNamesEnd = pDSNames + aDSNames.getLength();
193 :
194 0 : for ( ;pDSNames != pDSNamesEnd; ++pDSNames )
195 0 : m_pImpl->aDataSourceNames.insert( *pDSNames );
196 : }
197 : }
198 0 : catch( const Exception& )
199 : {
200 : OSL_FAIL( "ODataSourceContext::ODataSourceContext: caught an exception!" );
201 : }
202 0 : }
203 0 : ODataSourceContext::~ODataSourceContext()
204 : {
205 0 : delete(m_pImpl);
206 0 : }
207 :
208 :
209 0 : OUString& ODataSourceContext::disambiguate(OUString& _rDataSourceName)
210 : {
211 0 : OUString sCheck( _rDataSourceName );
212 0 : StringBag::const_iterator aPos = m_pImpl->aDataSourceNames.find( sCheck );
213 :
214 0 : sal_Int32 nPostfix = 1;
215 0 : while ( ( m_pImpl->aDataSourceNames.end() != aPos ) && ( nPostfix < 65535 ) )
216 : { // there already is a data source with this name
217 0 : sCheck = _rDataSourceName;
218 0 : sCheck += OUString::number( nPostfix++ );
219 :
220 0 : aPos = m_pImpl->aDataSourceNames.find( sCheck );
221 : }
222 :
223 0 : _rDataSourceName = sCheck;
224 0 : return _rDataSourceName;
225 : }
226 :
227 :
228 0 : void ODataSourceContext::getDataSourceNames( StringBag& _rNames ) const
229 : {
230 0 : _rNames = m_pImpl->aDataSourceNames;
231 0 : }
232 :
233 :
234 0 : ODataSource ODataSourceContext::createNewLDAP( const OUString& _rName)
235 : {
236 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:ldap:" );
237 : }
238 :
239 :
240 0 : ODataSource ODataSourceContext::createNewMORK( const OUString& _rName)
241 : {
242 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:mozilla" );
243 : }
244 :
245 :
246 0 : ODataSource ODataSourceContext::createNewThunderbird( const OUString& _rName )
247 : {
248 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:thunderbird" );
249 : }
250 :
251 :
252 0 : ODataSource ODataSourceContext::createNewEvolutionLdap( const OUString& _rName)
253 : {
254 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:ldap" );
255 : }
256 :
257 0 : ODataSource ODataSourceContext::createNewEvolutionGroupwise( const OUString& _rName)
258 : {
259 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:groupwise" );
260 : }
261 :
262 0 : ODataSource ODataSourceContext::createNewEvolution( const OUString& _rName)
263 : {
264 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:local" );
265 : }
266 :
267 :
268 0 : ODataSource ODataSourceContext::createNewKab( const OUString& _rName)
269 : {
270 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:kab" );
271 : }
272 :
273 :
274 0 : ODataSource ODataSourceContext::createNewMacab( const OUString& _rName)
275 : {
276 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:macab" );
277 : }
278 :
279 :
280 0 : ODataSource ODataSourceContext::createNewOutlook( const OUString& _rName)
281 : {
282 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlook" );
283 : }
284 :
285 :
286 0 : ODataSource ODataSourceContext::createNewOE( const OUString& _rName)
287 : {
288 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:outlookexp" );
289 : }
290 :
291 :
292 0 : ODataSource ODataSourceContext::createNewDBase( const OUString& _rName)
293 : {
294 0 : return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:dbase:" );
295 : }
296 :
297 :
298 : //= ODataSourceImpl
299 :
300 0 : struct ODataSourceImpl
301 : {
302 : public:
303 : Reference< XComponentContext > xORB; /// the service factory
304 : Reference< XPropertySet > xDataSource; /// the UNO data source
305 : ::utl::SharedUNOComponent< XConnection >
306 : xConnection;
307 : StringBag aTables; // the cached table names
308 : OUString sName;
309 : bool bTablesUpToDate; // table name cache up-to-date?
310 :
311 0 : ODataSourceImpl( const Reference< XComponentContext >& _rxORB )
312 : :xORB( _rxORB )
313 0 : ,bTablesUpToDate( false )
314 : {
315 0 : }
316 :
317 : ODataSourceImpl( const ODataSourceImpl& _rSource );
318 : };
319 :
320 :
321 0 : ODataSourceImpl::ODataSourceImpl( const ODataSourceImpl& _rSource )
322 : :xORB( _rSource.xORB )
323 : ,xDataSource( _rSource.xDataSource )
324 : ,xConnection( _rSource.xConnection )
325 : ,aTables( _rSource.aTables )
326 : ,sName( _rSource.sName )
327 0 : ,bTablesUpToDate( _rSource.bTablesUpToDate )
328 : {
329 0 : }
330 :
331 :
332 : //= ODataSource
333 :
334 :
335 0 : ODataSource::ODataSource( const ODataSource& _rSource )
336 0 : :m_pImpl( NULL )
337 : {
338 0 : *this = _rSource;
339 0 : }
340 :
341 :
342 0 : ODataSource& ODataSource::operator=( const ODataSource& _rSource )
343 : {
344 0 : if( this != &_rSource )
345 : {
346 0 : delete m_pImpl;
347 0 : m_pImpl = new ODataSourceImpl( *_rSource.m_pImpl );
348 : }
349 0 : return *this;
350 : }
351 :
352 :
353 0 : ODataSource::ODataSource( const Reference< XComponentContext >& _rxORB )
354 0 : :m_pImpl(new ODataSourceImpl(_rxORB))
355 : {
356 0 : }
357 :
358 :
359 0 : ODataSource::~ODataSource( )
360 : {
361 0 : delete m_pImpl;
362 0 : }
363 :
364 :
365 0 : void ODataSource::store()
366 : {
367 0 : if (!isValid())
368 : // nothing to do
369 0 : return;
370 : try
371 : {
372 0 : Reference< XDocumentDataSource > xDocAccess( m_pImpl->xDataSource, UNO_QUERY );
373 0 : Reference< XStorable > xStorable;
374 0 : if ( xDocAccess.is() )
375 0 : xStorable.set(xDocAccess->getDatabaseDocument(), css::uno::UNO_QUERY);
376 : OSL_ENSURE( xStorable.is(),"DataSource is no XStorable!" );
377 0 : if ( xStorable.is() )
378 0 : xStorable->storeAsURL(m_pImpl->sName,Sequence<PropertyValue>());
379 : }
380 0 : catch(const Exception&)
381 : {
382 : OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
383 : }
384 : }
385 :
386 0 : void ODataSource::registerDataSource( const OUString& _sRegisteredDataSourceName)
387 : {
388 0 : if (!isValid())
389 : // nothing to do
390 0 : return;
391 :
392 : try
393 : {
394 : // invalidate ourself
395 0 : lcl_registerDataSource(m_pImpl->xORB,_sRegisteredDataSourceName,m_pImpl->sName);
396 : }
397 0 : catch(const Exception&)
398 : {
399 : OSL_FAIL( "ODataSource::registerDataSource: caught an exception while creating the data source!" );
400 : }
401 : }
402 :
403 :
404 0 : void ODataSource::setDataSource( const Reference< XPropertySet >& _rxDS,const OUString& _sName, PackageAccessControl )
405 : {
406 0 : if (m_pImpl->xDataSource.get() == _rxDS.get())
407 : // nothing to do
408 0 : return;
409 :
410 0 : if ( isConnected() )
411 0 : disconnect();
412 :
413 0 : m_pImpl->sName = _sName;
414 0 : m_pImpl->xDataSource = _rxDS;
415 : }
416 :
417 :
418 0 : void ODataSource::remove()
419 : {
420 0 : if (!isValid())
421 : // nothing to do
422 0 : return;
423 :
424 : try
425 : {
426 : // invalidate ourself
427 0 : m_pImpl->xDataSource.clear();
428 : }
429 0 : catch(const Exception&)
430 : {
431 : OSL_FAIL( "ODataSource::remove: caught an exception while creating the data source!" );
432 : }
433 : }
434 :
435 :
436 0 : bool ODataSource::rename( const OUString& _rName )
437 : {
438 0 : if (!isValid())
439 : // nothing to do
440 0 : return false;
441 :
442 0 : m_pImpl->sName = _rName;
443 0 : return true;
444 : }
445 :
446 :
447 0 : OUString ODataSource::getName() const
448 : {
449 0 : if ( !isValid() )
450 0 : return OUString();
451 0 : return m_pImpl->sName;
452 : }
453 :
454 :
455 0 : bool ODataSource::hasTable( const OUString& _rTableName ) const
456 : {
457 0 : if ( !isConnected() )
458 0 : return false;
459 :
460 0 : const StringBag& aTables( getTableNames() );
461 0 : return aTables.find( _rTableName ) != aTables.end();
462 : }
463 :
464 :
465 0 : const StringBag& ODataSource::getTableNames() const
466 : {
467 0 : m_pImpl->aTables.clear();
468 0 : if ( !isConnected() )
469 : {
470 : OSL_FAIL( "ODataSource::getTableNames: not connected!" );
471 : }
472 : else
473 : {
474 : try
475 : {
476 : // get the tables container from the connection
477 0 : Reference< XTablesSupplier > xSuppTables( m_pImpl->xConnection.getTyped(), UNO_QUERY );
478 0 : Reference< XNameAccess > xTables;
479 0 : if ( xSuppTables.is( ) )
480 0 : xTables = xSuppTables->getTables();
481 : DBG_ASSERT( xTables.is(), "ODataSource::getTableNames: could not retrieve the tables container!" );
482 :
483 : // get the names
484 0 : Sequence< OUString > aTableNames;
485 0 : if ( xTables.is( ) )
486 0 : aTableNames = xTables->getElementNames( );
487 :
488 : // copy the names
489 0 : const OUString* pTableNames = aTableNames.getConstArray();
490 0 : const OUString* pTableNamesEnd = pTableNames + aTableNames.getLength();
491 0 : for (;pTableNames < pTableNamesEnd; ++pTableNames)
492 0 : m_pImpl->aTables.insert( *pTableNames );
493 : }
494 0 : catch(const Exception&)
495 : {
496 : }
497 : }
498 :
499 : // now the table cache is up-to-date
500 0 : m_pImpl->bTablesUpToDate = true;
501 0 : return m_pImpl->aTables;
502 : }
503 :
504 :
505 0 : bool ODataSource::connect( vcl::Window* _pMessageParent )
506 : {
507 0 : if ( isConnected( ) )
508 : // nothing to do
509 0 : return true;
510 :
511 :
512 : // create the interaction handler (needed for authentication and error handling)
513 0 : Reference< XInteractionHandler > xInteractions;
514 : try
515 : {
516 : xInteractions.set(
517 : InteractionHandler::createWithParent(m_pImpl->xORB, 0),
518 0 : UNO_QUERY);
519 : }
520 0 : catch(const Exception&)
521 : {
522 : }
523 :
524 :
525 : // failure to create the interaction handler is a serious issue ...
526 0 : if (!xInteractions.is())
527 : {
528 0 : OUString s_sInteractionHandlerServiceName("com.sun.star.task.InteractionHandler");
529 0 : if ( _pMessageParent )
530 0 : ShowServiceNotAvailableError( _pMessageParent, s_sInteractionHandlerServiceName, true );
531 0 : return false;
532 : }
533 :
534 :
535 : // open the connection
536 0 : Any aError;
537 0 : Reference< XConnection > xConnection;
538 : try
539 : {
540 0 : Reference< XCompletedConnection > xComplConn( m_pImpl->xDataSource, UNO_QUERY );
541 : DBG_ASSERT( xComplConn.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" );
542 0 : if ( xComplConn.is() )
543 0 : xConnection = xComplConn->connectWithCompletion( xInteractions );
544 : }
545 0 : catch( const SQLContext& e ) { aError <<= e; }
546 0 : catch( const SQLWarning& e ) { aError <<= e; }
547 0 : catch( const SQLException& e ) { aError <<= e; }
548 0 : catch( const Exception& )
549 : {
550 : OSL_FAIL( "ODataSource::connect: caught a generic exception!" );
551 : }
552 :
553 :
554 : // handle errors
555 0 : if ( aError.hasValue() && _pMessageParent )
556 : {
557 : try
558 : {
559 0 : SQLException aException;
560 0 : aError >>= aException;
561 0 : if ( aException.Message.isEmpty() )
562 : {
563 : // prepend some context info
564 0 : SQLContext aDetailedError;
565 0 : aDetailedError.Message = ModuleRes(RID_STR_NOCONNECTION).toString();
566 0 : aDetailedError.Details = ModuleRes(RID_STR_PLEASECHECKSETTINGS).toString();
567 0 : aDetailedError.NextException = aError;
568 : // handle (aka display) the new context info
569 0 : xInteractions->handle( new OInteractionRequest( makeAny( aDetailedError ) ) );
570 : }
571 : else
572 : {
573 : // handle (aka display) the original error
574 0 : xInteractions->handle( new OInteractionRequest( makeAny( aException ) ) );
575 0 : }
576 : }
577 0 : catch( const Exception& )
578 : {
579 : OSL_FAIL( "ODataSource::connect: caught an exception while trying to display the error!" );
580 : }
581 : }
582 :
583 0 : if ( !xConnection.is() )
584 0 : return false;
585 :
586 :
587 : // success
588 0 : m_pImpl->xConnection.reset( xConnection );
589 0 : m_pImpl->aTables.clear();
590 0 : m_pImpl->bTablesUpToDate = false;
591 :
592 0 : return true;
593 : }
594 :
595 :
596 0 : void ODataSource::disconnect( )
597 : {
598 0 : m_pImpl->xConnection.clear();
599 0 : m_pImpl->aTables.clear();
600 0 : m_pImpl->bTablesUpToDate = false;
601 0 : }
602 :
603 :
604 0 : bool ODataSource::isConnected( ) const
605 : {
606 0 : return m_pImpl->xConnection.is();
607 : }
608 :
609 :
610 0 : bool ODataSource::isValid() const
611 : {
612 0 : return m_pImpl && m_pImpl->xDataSource.is();
613 : }
614 :
615 0 : Reference< XPropertySet > ODataSource::getDataSource() const
616 : {
617 0 : return m_pImpl ? m_pImpl->xDataSource : Reference< XPropertySet >();
618 : }
619 :
620 :
621 : } // namespace abp
622 :
623 :
624 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|