xref: /core/ucb/source/core/ucb.cxx (revision 9e0b3423)
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 /**************************************************************************
22                                 TODO
23  **************************************************************************
24 
25  *************************************************************************/
26 #include <osl/diagnose.h>
27 #include <sal/log.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <comphelper/interfacecontainer2.hxx>
30 #include <comphelper/propertysequence.hxx>
31 #include <cppuhelper/queryinterface.hxx>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/ucb/DuplicateProviderException.hpp>
34 #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
35 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
36 #include <com/sun/star/ucb/XCommandInfo.hpp>
37 #include <com/sun/star/ucb/XContentProvider.hpp>
38 #include <com/sun/star/ucb/XContentProviderSupplier.hpp>
39 #include <com/sun/star/ucb/XParameterizedContentProvider.hpp>
40 #include <com/sun/star/ucb/XContentProviderFactory.hpp>
41 #include <com/sun/star/beans/PropertyValue.hpp>
42 #include <com/sun/star/configuration/theDefaultProvider.hpp>
43 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/uno/Any.hxx>
46 #include <ucbhelper/cancelcommandexecution.hxx>
47 #include <ucbhelper/getcomponentcontext.hxx>
48 #include "identify.hxx"
49 #include "ucbcmds.hxx"
50 
51 #include "ucb.hxx"
52 
53 using namespace comphelper;
54 using namespace com::sun::star::uno;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::ucb;
57 using namespace ucb_impl;
58 using namespace com::sun::star;
59 using namespace ucbhelper;
60 
61 
62 namespace {
63 
64 bool fillPlaceholders(OUString const & rInput,
65                       uno::Sequence< uno::Any > const & rReplacements,
66                       OUString * pOutput)
67 {
68     sal_Unicode const * p = rInput.getStr();
69     sal_Unicode const * pEnd = p + rInput.getLength();
70     sal_Unicode const * pCopy = p;
71     OUStringBuffer aBuffer;
72     while (p != pEnd)
73         switch (*p++)
74         {
75             case '&':
76                 if (pEnd - p >= 4
77                     && p[0] == 'a' && p[1] == 'm' && p[2] == 'p'
78                     && p[3] == ';')
79                 {
80                     aBuffer.append(pCopy, p - 1 - pCopy);
81                     aBuffer.append('&');
82                     p += 4;
83                     pCopy = p;
84                 }
85                 else if (pEnd - p >= 3
86                          && p[0] == 'l' && p[1] == 't' && p[2] == ';')
87                 {
88                     aBuffer.append(pCopy, p - 1 - pCopy);
89                     aBuffer.append('<');
90                     p += 3;
91                     pCopy = p;
92                 }
93                 else if (pEnd - p >= 3
94                          && p[0] == 'g' && p[1] == 't' && p[2] == ';')
95                 {
96                     aBuffer.append(pCopy, p - 1 - pCopy);
97                     aBuffer.append('>');
98                     p += 3;
99                     pCopy = p;
100                 }
101                 break;
102 
103             case '<':
104                 sal_Unicode const * q = p;
105                 while (q != pEnd && *q != '>')
106                     ++q;
107                 if (q == pEnd)
108                     break;
109                 OUString aKey(p, q - p);
110                 OUString aValue;
111                 bool bFound = false;
112                 for (sal_Int32 i = 2; i + 1 < rReplacements.getLength();
113                      i += 2)
114                 {
115                     OUString aReplaceKey;
116                     if ((rReplacements[i] >>= aReplaceKey)
117                         && aReplaceKey == aKey
118                         && (rReplacements[i + 1] >>= aValue))
119                     {
120                         bFound = true;
121                         break;
122                     }
123                 }
124                 if (!bFound)
125                     return false;
126                 aBuffer.append(pCopy, p - 1 - pCopy);
127                 aBuffer.append(aValue);
128                 p = q + 1;
129                 pCopy = p;
130                 break;
131         }
132     aBuffer.append(pCopy, pEnd - pCopy);
133     *pOutput = aBuffer.makeStringAndClear();
134     return true;
135 }
136 
137 void makeAndAppendXMLName(
138                 OUStringBuffer & rBuffer, const OUString & rIn )
139 {
140     sal_Int32 nCount = rIn.getLength();
141     for ( sal_Int32 n = 0; n < nCount; ++n )
142     {
143         const sal_Unicode c = rIn[ n ];
144         switch ( c )
145         {
146             case '&':
147                 rBuffer.append( "&amp;" );
148                 break;
149 
150             case '"':
151                 rBuffer.append( "&quot;" );
152                 break;
153 
154             case '\'':
155                 rBuffer.append( "&apos;" );
156                 break;
157 
158             case '<':
159                 rBuffer.append( "&lt;" );
160                 break;
161 
162             case '>':
163                 rBuffer.append( "&gt;" );
164                 break;
165 
166             default:
167                 rBuffer.append( c );
168                 break;
169         }
170     }
171 }
172 
173 bool createContentProviderData(
174     const OUString & rProvider,
175     const uno::Reference< container::XHierarchicalNameAccess >& rxHierNameAccess,
176     ContentProviderData & rInfo)
177 {
178     // Obtain service name.
179     OUStringBuffer aKeyBuffer (rProvider);
180     aKeyBuffer.append( "/ServiceName" );
181 
182     OUString aValue;
183     try
184     {
185         if ( !( rxHierNameAccess->getByHierarchicalName(
186                     aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
187         {
188             OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
189                         "Error getting item value!" );
190         }
191     }
192     catch (const container::NoSuchElementException&)
193     {
194         return false;
195     }
196 
197     rInfo.ServiceName = aValue;
198 
199     // Obtain URL Template.
200     aKeyBuffer.append(rProvider);
201     aKeyBuffer.append( "/URLTemplate" );
202 
203     if ( !( rxHierNameAccess->getByHierarchicalName(
204                 aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
205     {
206         OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
207                     "Error getting item value!" );
208     }
209 
210     rInfo.URLTemplate = aValue;
211 
212     // Obtain Arguments.
213     aKeyBuffer.append(rProvider);
214     aKeyBuffer.append( "/Arguments" );
215 
216     if ( !( rxHierNameAccess->getByHierarchicalName(
217                 aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
218     {
219         OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
220                     "Error getting item value!" );
221     }
222 
223     rInfo.Arguments = aValue;
224     return true;
225 }
226 
227 }
228 
229 
230 // UniversalContentBroker Implementation.
231 
232 
233 UniversalContentBroker::UniversalContentBroker(
234     const Reference< css::uno::XComponentContext >& xContext )
235 : m_xContext( xContext ),
236   m_nCommandId( 0 )
237 {
238     OSL_ENSURE( m_xContext.is(),
239                 "UniversalContentBroker ctor: No service manager" );
240 }
241 
242 
243 // virtual
244 UniversalContentBroker::~UniversalContentBroker()
245 {
246 }
247 
248 
249 // XInterface methods.
250 void SAL_CALL UniversalContentBroker::acquire()
251     throw()
252 {
253     OWeakObject::acquire();
254 }
255 
256 void SAL_CALL UniversalContentBroker::release()
257     throw()
258 {
259     OWeakObject::release();
260 }
261 
262 css::uno::Any SAL_CALL UniversalContentBroker::queryInterface( const css::uno::Type & rType )
263 {
264     css::uno::Any aRet = cppu::queryInterface( rType,
265                                                static_cast< XUniversalContentBroker* >(this),
266                                                static_cast< XTypeProvider* >(this),
267                                                static_cast< XComponent* >(this),
268                                                static_cast< XServiceInfo* >(this),
269                                                static_cast< XInitialization* >(this),
270                                                static_cast< XContentProviderManager* >(this),
271                                                static_cast< XContentProvider* >(this),
272                                                static_cast< XContentIdentifierFactory* >(this),
273                                                static_cast< XCommandProcessor* >(this)
274                                                );
275     return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
276 }
277 
278 // XTypeProvider methods.
279 
280 
281 XTYPEPROVIDER_IMPL_9( UniversalContentBroker,
282                       XUniversalContentBroker,
283                       XTypeProvider,
284                       XComponent,
285                       XServiceInfo,
286                       XInitialization,
287                       XContentProviderManager,
288                       XContentProvider,
289                       XContentIdentifierFactory,
290                       XCommandProcessor );
291 
292 
293 // XComponent methods.
294 
295 
296 // virtual
297 void SAL_CALL UniversalContentBroker::dispose()
298 {
299     if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
300     {
301         EventObject aEvt;
302         aEvt.Source = static_cast< XComponent* >(this);
303         m_pDisposeEventListeners->disposeAndClear( aEvt );
304     }
305 
306     if ( m_xNotifier.is() )
307         m_xNotifier->removeChangesListener( this );
308 }
309 
310 
311 // virtual
312 void SAL_CALL UniversalContentBroker::addEventListener(
313                             const Reference< XEventListener >& Listener )
314 {
315     if ( !m_pDisposeEventListeners )
316         m_pDisposeEventListeners.reset( new OInterfaceContainerHelper2( m_aMutex ) );
317 
318     m_pDisposeEventListeners->addInterface( Listener );
319 }
320 
321 
322 // virtual
323 void SAL_CALL UniversalContentBroker::removeEventListener(
324                             const Reference< XEventListener >& Listener )
325 {
326     if ( m_pDisposeEventListeners )
327         m_pDisposeEventListeners->removeInterface( Listener );
328 
329     // Note: Don't want to delete empty container here -> performance.
330 }
331 
332 
333 // XServiceInfo methods.
334 
335 XSERVICEINFO_COMMOM_IMPL( UniversalContentBroker,
336                           "com.sun.star.comp.ucb.UniversalContentBroker" )
337 /// @throws css::uno::Exception
338 static css::uno::Reference< css::uno::XInterface >
339 UniversalContentBroker_CreateInstance( const css::uno::Reference< css::lang::XMultiServiceFactory> & rSMgr )
340 {
341     css::lang::XServiceInfo* pX = new UniversalContentBroker( ucbhelper::getComponentContext(rSMgr) );
342     return css::uno::Reference< css::uno::XInterface >::query( pX );
343 }
344 
345 css::uno::Sequence< OUString >
346 UniversalContentBroker::getSupportedServiceNames_Static()
347 {
348     css::uno::Sequence< OUString > aSNS { UCB_SERVICE_NAME };
349     return aSNS;
350 }
351 
352 // Service factory implementation.
353 
354 
355 ONE_INSTANCE_SERVICE_FACTORY_IMPL( UniversalContentBroker );
356 
357 
358 // XInitialization methods.
359 
360 
361 // virtual
362 void SAL_CALL UniversalContentBroker::initialize( const css::uno::Sequence< Any >& aArguments )
363 {
364     {
365         osl::MutexGuard aGuard(m_aMutex);
366         if (m_aArguments.hasElements())
367         {
368             if (aArguments.hasElements()
369                 && !(m_aArguments.getLength() == 2
370                      && aArguments.getLength() == 2
371                      && m_aArguments[0] == aArguments[0]
372                      && m_aArguments[1] == aArguments[1]))
373             {
374                 throw IllegalArgumentException(
375                     "UCB reinitialized with different arguments",
376                     static_cast< cppu::OWeakObject * >(this), 0);
377             }
378             return;
379         }
380         if (!aArguments.hasElements())
381         {
382             m_aArguments.realloc(2);
383             m_aArguments[0] <<= OUString("Local");
384             m_aArguments[1] <<= OUString("Office");
385         }
386         else
387         {
388             m_aArguments = aArguments;
389         }
390     }
391     configureUcb();
392 }
393 
394 
395 // XContentProviderManager methods.
396 
397 
398 // virtual
399 Reference< XContentProvider > SAL_CALL
400 UniversalContentBroker::registerContentProvider(
401                             const Reference< XContentProvider >& Provider,
402                             const OUString& Scheme,
403                             sal_Bool ReplaceExisting )
404 {
405     osl::MutexGuard aGuard(m_aMutex);
406 
407     ProviderMap_Impl::iterator aIt;
408     try
409     {
410         aIt = m_aProviders.find(Scheme);
411     }
412     catch (const IllegalArgumentException&)
413     {
414         return nullptr; //@@@
415     }
416 
417     Reference< XContentProvider > xPrevious;
418     if (aIt == m_aProviders.end())
419     {
420         ProviderList_Impl aList;
421         aList.push_front( ProviderListEntry_Impl(Provider) );
422         try
423         {
424             m_aProviders.add(Scheme, aList);
425         }
426         catch (const IllegalArgumentException&)
427         {
428             return nullptr; //@@@
429         }
430     }
431     else
432     {
433         if (!ReplaceExisting)
434             throw DuplicateProviderException();
435 
436         ProviderList_Impl & rList = aIt->getValue();
437         xPrevious = rList.front().getProvider();
438         rList.push_front( ProviderListEntry_Impl(Provider) );
439     }
440 
441     return xPrevious;
442 }
443 
444 
445 // virtual
446 void SAL_CALL UniversalContentBroker::deregisterContentProvider(
447                               const Reference< XContentProvider >& Provider,
448                             const OUString& Scheme )
449 {
450     osl::MutexGuard aGuard(m_aMutex);
451 
452     ProviderMap_Impl::iterator aMapIt;
453     try
454     {
455         aMapIt = m_aProviders.find(Scheme);
456     }
457     catch (const IllegalArgumentException&)
458     {
459         return; //@@@
460     }
461 
462     if (aMapIt != m_aProviders.end())
463     {
464         ProviderList_Impl & rList = aMapIt->getValue();
465 
466         auto aListIt = std::find_if(rList.begin(), rList.end(),
467             [&Provider](const ProviderListEntry_Impl& rEntry) { return rEntry.getProvider() == Provider; });
468         if (aListIt != rList.end())
469             rList.erase(aListIt);
470 
471         if (rList.empty())
472             m_aProviders.erase(aMapIt);
473     }
474 }
475 
476 
477 // virtual
478 css::uno::Sequence< ContentProviderInfo > SAL_CALL
479                             UniversalContentBroker::queryContentProviders()
480 {
481     // Return a list with information about active(!) content providers.
482 
483     osl::MutexGuard aGuard(m_aMutex);
484 
485     css::uno::Sequence< ContentProviderInfo > aSeq( m_aProviders.size() );
486     ContentProviderInfo* pInfo = aSeq.getArray();
487 
488     ProviderMap_Impl::const_iterator end = m_aProviders.end();
489     for (ProviderMap_Impl::const_iterator it(m_aProviders.begin()); it != end;
490          ++it)
491     {
492         // Note: Active provider is always the first list element.
493         pInfo->ContentProvider = it->getValue().front().getProvider();
494         pInfo->Scheme = it->getRegexp();
495         ++pInfo;
496     }
497 
498     return aSeq;
499 }
500 
501 
502 // virtual
503 Reference< XContentProvider > SAL_CALL
504         UniversalContentBroker::queryContentProvider( const OUString&
505                                                           Identifier )
506 {
507     return queryContentProvider( Identifier, false );
508 }
509 
510 
511 // XContentProvider methods.
512 
513 
514 // virtual
515 Reference< XContent > SAL_CALL UniversalContentBroker::queryContent(
516                         const Reference< XContentIdentifier >& Identifier )
517 {
518 
519     // Let the content provider for the scheme given with the content
520     // identifier create the XContent instance.
521 
522 
523     if ( !Identifier.is() )
524         return Reference< XContent >();
525 
526     Reference< XContentProvider > xProv =
527         queryContentProvider( Identifier->getContentIdentifier(), true );
528     if ( xProv.is() )
529         return  xProv->queryContent( Identifier );
530 
531     return Reference< XContent >();
532 }
533 
534 
535 // virtual
536 sal_Int32 SAL_CALL UniversalContentBroker::compareContentIds(
537                                 const Reference< XContentIdentifier >& Id1,
538                                 const Reference< XContentIdentifier >& Id2 )
539 {
540     OUString aURI1( Id1->getContentIdentifier() );
541     OUString aURI2( Id2->getContentIdentifier() );
542 
543     Reference< XContentProvider > xProv1
544                             = queryContentProvider( aURI1, true );
545     Reference< XContentProvider > xProv2
546                             = queryContentProvider( aURI2, true );
547 
548     // When both identifiers belong to the same provider, let that provider
549     // compare them; otherwise, simply compare the URI strings (which must
550     // be different):
551     if ( xProv1.is() && ( xProv1 == xProv2 ) )
552         return xProv1->compareContentIds( Id1, Id2 );
553     else
554         return aURI1.compareTo( aURI2 );
555 }
556 
557 
558 // XContentIdentifierFactory methods.
559 
560 
561 // virtual
562 Reference< XContentIdentifier > SAL_CALL
563         UniversalContentBroker::createContentIdentifier(
564                                             const OUString& ContentId )
565 {
566 
567     // Let the content provider for the scheme given with content
568     // identifier create the XContentIdentifier instance, if he supports
569     // the XContentIdentifierFactory interface. Otherwise create standard
570     // implementation object for XContentIdentifier.
571 
572 
573     Reference< XContentIdentifier > xIdentifier;
574 
575     Reference< XContentProvider > xProv
576                             = queryContentProvider( ContentId, true );
577     if ( xProv.is() )
578     {
579         Reference< XContentIdentifierFactory > xFac( xProv, UNO_QUERY );
580         if ( xFac.is() )
581             xIdentifier = xFac->createContentIdentifier( ContentId );
582     }
583 
584     if ( !xIdentifier.is() )
585         xIdentifier = new ContentIdentifier( ContentId );
586 
587     return xIdentifier;
588 }
589 
590 
591 // XCommandProcessor methods.
592 
593 
594 // virtual
595 sal_Int32 SAL_CALL UniversalContentBroker::createCommandIdentifier()
596 {
597     osl::MutexGuard aGuard( m_aMutex );
598 
599     // Just increase counter on every call to generate an identifier.
600     return ++m_nCommandId;
601 }
602 
603 
604 // virtual
605 Any SAL_CALL UniversalContentBroker::execute(
606                           const Command& aCommand,
607                           sal_Int32,
608                           const Reference< XCommandEnvironment >& Environment )
609 {
610     Any aRet;
611 
612 
613     // Note: Don't forget to adapt ucb_commands::CommandProcessorInfo
614     //       ctor in ucbcmds.cxx when adding new commands!
615 
616 
617     if ( ( aCommand.Handle == GETCOMMANDINFO_HANDLE ) || aCommand.Name == GETCOMMANDINFO_NAME )
618     {
619 
620         // getCommandInfo
621 
622 
623         aRet <<= getCommandInfo();
624     }
625     else if ( ( aCommand.Handle == GLOBALTRANSFER_HANDLE ) || aCommand.Name == GLOBALTRANSFER_NAME )
626     {
627 
628         // globalTransfer
629 
630 
631         GlobalTransferCommandArgument2 aTransferArg;
632         if ( !( aCommand.Argument >>= aTransferArg ) )
633         {
634             GlobalTransferCommandArgument aArg;
635             if ( !( aCommand.Argument >>= aArg ) )
636             {
637                 ucbhelper::cancelCommandExecution(
638                     makeAny( IllegalArgumentException(
639                                     "Wrong argument type!",
640                                     static_cast< cppu::OWeakObject * >( this ),
641                                     -1 ) ),
642                     Environment );
643                 // Unreachable
644             }
645 
646             // Copy infos into the new structure
647             aTransferArg.Operation = aArg.Operation;
648             aTransferArg.SourceURL = aArg.SourceURL;
649             aTransferArg.TargetURL = aArg.TargetURL;
650             aTransferArg.NewTitle = aArg.NewTitle;
651             aTransferArg.NameClash = aArg.NameClash;
652         }
653 
654         globalTransfer( aTransferArg, Environment );
655     }
656     else if ( ( aCommand.Handle == CHECKIN_HANDLE ) || aCommand.Name == CHECKIN_NAME )
657     {
658         ucb::CheckinArgument aCheckinArg;
659         if ( !( aCommand.Argument >>= aCheckinArg ) )
660         {
661             ucbhelper::cancelCommandExecution(
662                 makeAny( IllegalArgumentException(
663                                 "Wrong argument type!",
664                                 static_cast< cppu::OWeakObject * >( this ),
665                                 -1 ) ),
666                 Environment );
667             // Unreachable
668         }
669         aRet = checkIn( aCheckinArg, Environment );
670     }
671     else
672     {
673 
674         // Unknown command
675 
676 
677         ucbhelper::cancelCommandExecution(
678             makeAny( UnsupportedCommandException(
679                             OUString(),
680                             static_cast< cppu::OWeakObject * >( this ) ) ),
681             Environment );
682         // Unreachable
683     }
684 
685     return aRet;
686 }
687 
688 
689 // XCommandProcessor2 methods.
690 
691 
692 // virtual
693 void SAL_CALL UniversalContentBroker::releaseCommandIdentifier(sal_Int32 /*aCommandId*/)
694 {
695     // @@@ Not implemented ( yet).
696 }
697 
698 
699 // virtual
700 void SAL_CALL UniversalContentBroker::abort( sal_Int32 )
701 {
702     // @@@ Not implemented ( yet).
703 }
704 
705 
706 // XChangesListener methods
707 
708 
709 // virtual
710 void SAL_CALL UniversalContentBroker::changesOccurred( const util::ChangesEvent& Event )
711 {
712     if ( Event.Changes.hasElements() )
713     {
714         uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess;
715         Event.Base >>= xHierNameAccess;
716 
717         OSL_ASSERT( xHierNameAccess.is() );
718 
719         ContentProviderDataList aData;
720         for ( const util::ElementChange& rElem : Event.Changes )
721         {
722             OUString aKey;
723             rElem.Accessor >>= aKey;
724 
725             ContentProviderData aInfo;
726 
727             // Removal of UCPs from the configuration leads to changesOccurred
728             // notifications, too, but it is hard to tell for a given
729             // ElementChange whether it is an addition or a removal, so as a
730             // heuristic consider as removals those that cause a
731             // NoSuchElementException in createContentProviderData.
732 
733             // For now, removal of UCPs from the configuration is simply ignored
734             // (and not reflected in the UCB's data structures):
735             if (createContentProviderData(aKey, xHierNameAccess, aInfo))
736             {
737                 aData.push_back(aInfo);
738             }
739         }
740 
741         prepareAndRegister(aData);
742     }
743 }
744 
745 
746 // XEventListener methods
747 
748 
749 // virtual
750 void SAL_CALL UniversalContentBroker::disposing(const lang::EventObject&)
751 {
752     if ( m_xNotifier.is() )
753     {
754         osl::Guard< osl::Mutex > aGuard( m_aMutex );
755 
756         if ( m_xNotifier.is() )
757             m_xNotifier.clear();
758     }
759 }
760 
761 
762 // Non-interface methods
763 
764 
765 Reference< XContentProvider > UniversalContentBroker::queryContentProvider(
766                                 const OUString& Identifier,
767                                 bool bResolved )
768 {
769     osl::MutexGuard aGuard( m_aMutex );
770 
771     ProviderList_Impl const * pList = m_aProviders.map( Identifier );
772     return pList ? bResolved ? pList->front().getResolvedProvider()
773                              : pList->front().getProvider()
774                  : Reference< XContentProvider >();
775 }
776 
777 void UniversalContentBroker::configureUcb()
778 {
779     OUString aKey1;
780     OUString aKey2;
781     if (m_aArguments.getLength() < 2
782         || !(m_aArguments[0] >>= aKey1) || !(m_aArguments[1] >>= aKey2))
783     {
784         OSL_FAIL("UniversalContentBroker::configureUcb(): Bad arguments");
785         return;
786     }
787 
788     ContentProviderDataList aData;
789     if (!getContentProviderData(aKey1, aKey2, aData))
790     {
791         SAL_WARN( "ucb", "No configuration");
792         return;
793     }
794 
795     prepareAndRegister(aData);
796 }
797 
798 void UniversalContentBroker::prepareAndRegister(
799     const ContentProviderDataList& rData)
800 {
801     for (const auto& rContentProviderData : rData)
802     {
803         OUString aProviderArguments;
804         if (fillPlaceholders(rContentProviderData.Arguments,
805                              m_aArguments,
806                              &aProviderArguments))
807         {
808             registerAtUcb(this,
809                           m_xContext,
810                           rContentProviderData.ServiceName,
811                           aProviderArguments,
812                           rContentProviderData.URLTemplate);
813 
814         }
815         else
816             OSL_FAIL("UniversalContentBroker::prepareAndRegister(): Bad argument placeholders");
817     }
818 }
819 
820 
821 bool UniversalContentBroker::getContentProviderData(
822             const OUString & rKey1,
823             const OUString & rKey2,
824             ContentProviderDataList & rListToFill )
825 {
826     if ( !m_xContext.is() || rKey1.isEmpty() || rKey2.isEmpty() )
827     {
828         OSL_FAIL( "UniversalContentBroker::getContentProviderData - Invalid argument!" );
829         return false;
830     }
831 
832     try
833     {
834         uno::Reference< lang::XMultiServiceFactory > xConfigProv =
835                 configuration::theDefaultProvider::get( m_xContext );
836 
837         OUStringBuffer aFullPath;
838         aFullPath.append(
839                 "/org.openoffice.ucb.Configuration/ContentProviders"
840                 "/['" );
841         makeAndAppendXMLName( aFullPath, rKey1 );
842         aFullPath.append( "']/SecondaryKeys/['" );
843         makeAndAppendXMLName( aFullPath, rKey2 );
844         aFullPath.append( "']/ProviderData" );
845 
846         uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
847         {
848             {"nodepath", uno::Any(aFullPath.makeStringAndClear())}
849         }));
850 
851         uno::Reference< uno::XInterface > xInterface(
852                 xConfigProv->createInstanceWithArguments(
853                     "com.sun.star.configuration.ConfigurationAccess",
854                     aArguments ) );
855 
856         if ( !m_xNotifier.is() )
857         {
858             m_xNotifier.set( xInterface, uno::UNO_QUERY_THROW );
859 
860             m_xNotifier->addChangesListener( this );
861         }
862 
863         uno::Reference< container::XNameAccess > xNameAccess(
864                                             xInterface, uno::UNO_QUERY_THROW );
865 
866         const uno::Sequence< OUString > aElems = xNameAccess->getElementNames();
867 
868         if ( aElems.hasElements() )
869         {
870             uno::Reference< container::XHierarchicalNameAccess >
871                                 xHierNameAccess( xInterface, uno::UNO_QUERY_THROW );
872 
873             // Iterate over children.
874             for ( const auto& rElem : aElems )
875             {
876 
877                 try
878                 {
879 
880                     ContentProviderData aInfo;
881 
882                     OUStringBuffer aElemBuffer;
883                     aElemBuffer.append( "['" );
884                     makeAndAppendXMLName( aElemBuffer, rElem );
885                     aElemBuffer.append( "']" );
886 
887                     OSL_VERIFY(
888                         createContentProviderData(
889                             aElemBuffer.makeStringAndClear(), xHierNameAccess,
890                             aInfo));
891 
892                     rListToFill.push_back( aInfo );
893                 }
894                 catch (const container::NoSuchElementException&)
895                 {
896                     // getByHierarchicalName
897                     OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
898                                 "caught NoSuchElementException!" );
899                 }
900             }
901         }
902     }
903     catch (const uno::RuntimeException&)
904     {
905         SAL_WARN( "ucb", "caught RuntimeException!" );
906         return false;
907     }
908     catch (const uno::Exception&)
909     {
910         // createInstance, createInstanceWithArguments
911 
912         SAL_WARN( "ucb", "caught Exception!" );
913         return false;
914     }
915 
916     return true;
917 }
918 
919 
920 // ProviderListEntry_Impl implementation.
921 
922 
923 Reference< XContentProvider > const & ProviderListEntry_Impl::resolveProvider() const
924 {
925     if ( !m_xResolvedProvider.is() )
926     {
927         Reference< XContentProviderSupplier > xSupplier(
928                                                     m_xProvider, UNO_QUERY );
929         if ( xSupplier.is() )
930             m_xResolvedProvider = xSupplier->getContentProvider();
931 
932         if ( !m_xResolvedProvider.is() )
933             m_xResolvedProvider = m_xProvider;
934     }
935 
936     return m_xResolvedProvider;
937 }
938 
939 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
940