1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <com/sun/star/beans/IllegalTypeException.hpp>
23 #include <com/sun/star/beans/PropertyExistException.hpp>
24 #include <com/sun/star/beans/XPropertyAccess.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XNamed.hpp>
27 #include <com/sun/star/ucb/Store.hpp>
28 #include <com/sun/star/ucb/XPropertySetRegistry.hpp>
29 #include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
30 #include <cppuhelper/supportsservice.hxx>
31 #include <cppuhelper/queryinterface.hxx>
32 #include <ucbhelper/contenthelper.hxx>
33 #include <ucbhelper/contentidentifier.hxx>
34 #include <ucbhelper/providerhelper.hxx>
35 #include <ucbhelper/macros.hxx>
37 #include <osl/diagnose.h>
38 #include <osl/mutex.hxx>
39 #include <cppuhelper/weakref.hxx>
41 #include <unordered_map>
43 using namespace com::sun::star
;
45 namespace ucbhelper_impl
48 typedef std::unordered_map
51 uno::WeakReference
< ucb::XContent
>
55 struct ContentProviderImplHelper_Impl
57 uno::Reference
< css::ucb::XPropertySetRegistry
> m_xPropertySetRegistry
;
61 } // namespace ucbhelper_impl
65 ContentProviderImplHelper::ContentProviderImplHelper(
66 const uno::Reference
< uno::XComponentContext
>& rxContext
)
67 : m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl
),
68 m_xContext( rxContext
)
73 ContentProviderImplHelper::~ContentProviderImplHelper()
78 void SAL_CALL
ContentProviderImplHelper::acquire()
81 OWeakObject::acquire();
84 void SAL_CALL
ContentProviderImplHelper::release()
87 OWeakObject::release();
90 css::uno::Any SAL_CALL
ContentProviderImplHelper::queryInterface( const css::uno::Type
& rType
)
92 css::uno::Any aRet
= cppu::queryInterface( rType
,
93 static_cast< lang::XTypeProvider
* >(this),
94 static_cast< lang::XServiceInfo
* >(this),
95 static_cast< css::ucb::XContentProvider
* >(this)
97 return aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
);
100 XTYPEPROVIDER_IMPL_3( ContentProviderImplHelper
,
103 css::ucb::XContentProvider
);
106 sal_Bool SAL_CALL
ContentProviderImplHelper::supportsService(
107 const OUString
& ServiceName
)
109 return cppu::supportsService(this, ServiceName
);
113 sal_Int32 SAL_CALL
ContentProviderImplHelper::compareContentIds(
114 const uno::Reference
< css::ucb::XContentIdentifier
>& Id1
,
115 const uno::Reference
< css::ucb::XContentIdentifier
>& Id2
)
117 // Simply do a string compare.
119 OUString
aURL1( Id1
->getContentIdentifier() );
120 OUString
aURL2( Id2
->getContentIdentifier() );
122 return aURL1
.compareTo( aURL2
);
125 void ContentProviderImplHelper::cleanupRegisteredContents()
127 osl::MutexGuard
aGuard( m_aMutex
);
129 ucbhelper_impl::Contents::iterator it
130 = m_pImpl
->m_aContents
.begin();
131 while( it
!= m_pImpl
->m_aContents
.end() )
133 uno::Reference
< ucb::XContent
> xContent( (*it
).second
);
134 if ( !xContent
.is() )
136 ucbhelper_impl::Contents::iterator tmp
= it
;
138 m_pImpl
->m_aContents
.erase( tmp
);
147 void ContentProviderImplHelper::removeContent( ContentImplHelper
* pContent
)
149 osl::MutexGuard
aGuard( m_aMutex
);
151 cleanupRegisteredContents();
154 pContent
->getIdentifier()->getContentIdentifier() );
156 ucbhelper_impl::Contents::iterator it
= m_pImpl
->m_aContents
.find( aURL
);
158 if ( it
!= m_pImpl
->m_aContents
.end() )
159 m_pImpl
->m_aContents
.erase( it
);
162 rtl::Reference
< ContentImplHelper
>
163 ContentProviderImplHelper::queryExistingContent(
164 const uno::Reference
< css::ucb::XContentIdentifier
>& Identifier
)
166 return queryExistingContent( Identifier
->getContentIdentifier() );
169 rtl::Reference
< ContentImplHelper
>
170 ContentProviderImplHelper::queryExistingContent( const OUString
& rURL
)
172 osl::MutexGuard
aGuard( m_aMutex
);
174 cleanupRegisteredContents();
176 // Check, if a content with given id already exists...
178 ucbhelper_impl::Contents::const_iterator it
179 = m_pImpl
->m_aContents
.find( rURL
);
180 if ( it
!= m_pImpl
->m_aContents
.end() )
182 uno::Reference
< ucb::XContent
> xContent( (*it
).second
);
185 return rtl::Reference
< ContentImplHelper
>(
186 static_cast< ContentImplHelper
* >( xContent
.get() ) );
189 return rtl::Reference
< ContentImplHelper
>();
192 void ContentProviderImplHelper::queryExistingContents(
193 ContentRefList
& rContents
)
195 osl::MutexGuard
aGuard( m_aMutex
);
197 cleanupRegisteredContents();
199 for ( const auto& rContent
: m_pImpl
->m_aContents
)
201 uno::Reference
< ucb::XContent
> xContent( rContent
.second
);
204 rContents
.emplace_back(
205 static_cast< ContentImplHelper
* >( xContent
.get() ) );
210 void ContentProviderImplHelper::registerNewContent(
211 const uno::Reference
< ucb::XContent
> & xContent
)
215 osl::MutexGuard
aGuard( m_aMutex
);
217 cleanupRegisteredContents();
220 xContent
->getIdentifier()->getContentIdentifier() );
221 ucbhelper_impl::Contents::const_iterator it
222 = m_pImpl
->m_aContents
.find( aURL
);
223 if ( it
== m_pImpl
->m_aContents
.end() )
224 m_pImpl
->m_aContents
[ aURL
] = xContent
;
228 uno::Reference
< css::ucb::XPropertySetRegistry
>
229 ContentProviderImplHelper::getAdditionalPropertySetRegistry()
231 // Get propertyset registry.
233 osl::MutexGuard
aGuard( m_aMutex
);
235 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
237 uno::Reference
< css::ucb::XPropertySetRegistryFactory
>
238 xRegFac
= css::ucb::Store::create( m_xContext
);
240 // Open/create a registry.
241 m_pImpl
->m_xPropertySetRegistry
242 = xRegFac
->createPropertySetRegistry( OUString() );
244 OSL_ENSURE( m_pImpl
->m_xPropertySetRegistry
.is(),
245 "ContentProviderImplHelper::getAdditionalPropertySet - "
246 "Error opening registry!" );
249 return m_pImpl
->m_xPropertySetRegistry
;
252 uno::Reference
< css::ucb::XPersistentPropertySet
>
253 ContentProviderImplHelper::getAdditionalPropertySet(
254 const OUString
& rKey
, bool bCreate
)
256 // Get propertyset registry.
257 getAdditionalPropertySetRegistry();
259 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
261 // Open/create persistent property set.
262 return m_pImpl
->m_xPropertySetRegistry
->openPropertySet(
266 return uno::Reference
< css::ucb::XPersistentPropertySet
>();
269 bool ContentProviderImplHelper::renameAdditionalPropertySet(
270 const OUString
& rOldKey
,
271 const OUString
& rNewKey
,
274 if ( rOldKey
== rNewKey
)
277 osl::MutexGuard
aGuard( m_aMutex
);
281 // Get propertyset registry.
282 getAdditionalPropertySetRegistry();
284 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
286 uno::Reference
< container::XNameAccess
> xNameAccess(
287 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
288 if ( xNameAccess
.is() )
290 uno::Sequence
< OUString
> aKeys
291 = xNameAccess
->getElementNames();
292 sal_Int32 nCount
= aKeys
.getLength();
295 OUString aOldKeyWithSlash
= rOldKey
;
296 OUString aOldKeyWithoutSlash
;
297 if ( !aOldKeyWithSlash
.endsWith("/") )
299 aOldKeyWithSlash
+= "/";
300 aOldKeyWithoutSlash
= rOldKey
;
302 else if ( !rOldKey
.isEmpty() )
304 = rOldKey
.copy( 0, rOldKey
.getLength() - 1 );
306 const OUString
* pKeys
= aKeys
.getConstArray();
307 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
309 const OUString
& rKey
= pKeys
[ n
];
310 if ( rKey
.startsWith( aOldKeyWithSlash
)
311 || rKey
== aOldKeyWithoutSlash
)
315 0, rOldKey
.getLength(), rNewKey
);
316 if ( !renameAdditionalPropertySet(
317 rKey
, aNewKey
, false ) )
331 // Get old property set, if exists.
332 uno::Reference
< css::ucb::XPersistentPropertySet
> xOldSet
333 = getAdditionalPropertySet( rOldKey
, false );
336 // Rename property set.
337 uno::Reference
< container::XNamed
> xNamed(
338 xOldSet
, uno::UNO_QUERY
);
341 // ??? throws no exceptions and has no return value ???
342 xNamed
->setName( rNewKey
);
351 bool ContentProviderImplHelper::copyAdditionalPropertySet(
352 const OUString
& rSourceKey
,
353 const OUString
& rTargetKey
,
356 if ( rSourceKey
== rTargetKey
)
359 osl::MutexGuard
aGuard( m_aMutex
);
363 // Get propertyset registry.
364 getAdditionalPropertySetRegistry();
366 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
368 uno::Reference
< container::XNameAccess
> xNameAccess(
369 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
370 if ( xNameAccess
.is() )
372 uno::Sequence
< OUString
> aKeys
373 = xNameAccess
->getElementNames();
374 sal_Int32 nCount
= aKeys
.getLength();
377 OUString aSrcKeyWithSlash
= rSourceKey
;
378 OUString aSrcKeyWithoutSlash
;
379 if ( !aSrcKeyWithSlash
.endsWith("/") )
381 aSrcKeyWithSlash
+= "/";
382 aSrcKeyWithoutSlash
= rSourceKey
;
384 else if ( !rSourceKey
.isEmpty() )
385 aSrcKeyWithoutSlash
= rSourceKey
.copy(
386 0, rSourceKey
.getLength() - 1 );
388 const OUString
* pKeys
= aKeys
.getConstArray();
389 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
391 const OUString
& rKey
= pKeys
[ n
];
392 if ( rKey
.startsWith(aSrcKeyWithSlash
)
393 || rKey
== aSrcKeyWithoutSlash
)
397 0, rSourceKey
.getLength(), rTargetKey
);
398 if ( !copyAdditionalPropertySet(
399 rKey
, aNewKey
, false ) )
413 // Get old property set, if exists.
414 uno::Reference
< css::ucb::XPersistentPropertySet
>
415 xOldPropSet
= getAdditionalPropertySet( rSourceKey
, false );
416 if ( !xOldPropSet
.is() )
419 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
420 = xOldPropSet
->getPropertySetInfo();
421 if ( !xPropSetInfo
.is() )
424 uno::Reference
< beans::XPropertyAccess
> xOldPropAccess(
425 xOldPropSet
, uno::UNO_QUERY
);
426 if ( !xOldPropAccess
.is() )
429 // Obtain all values from old set.
430 uno::Sequence
< beans::PropertyValue
> aValues
431 = xOldPropAccess
->getPropertyValues();
432 sal_Int32 nCount
= aValues
.getLength();
434 uno::Sequence
< beans::Property
> aProps
435 = xPropSetInfo
->getProperties();
439 // Fail, if property set with new key already exists.
440 uno::Reference
< css::ucb::XPersistentPropertySet
>
442 = getAdditionalPropertySet( rTargetKey
, false );
443 if ( xNewPropSet
.is() )
446 // Create new, empty set.
447 xNewPropSet
= getAdditionalPropertySet( rTargetKey
, true );
448 if ( !xNewPropSet
.is() )
451 uno::Reference
< beans::XPropertyContainer
> xNewPropContainer(
452 xNewPropSet
, uno::UNO_QUERY
);
453 if ( !xNewPropContainer
.is() )
456 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
458 const beans::PropertyValue
& rValue
= aValues
[ n
];
460 sal_Int16 nAttribs
= 0;
461 for ( sal_Int32 m
= 0; m
< aProps
.getLength(); ++m
)
463 if ( aProps
[ m
].Name
== rValue
.Name
)
465 nAttribs
= aProps
[ m
].Attributes
;
472 xNewPropContainer
->addProperty(
473 rValue
.Name
, nAttribs
, rValue
.Value
);
475 catch ( beans::PropertyExistException
& )
478 catch ( beans::IllegalTypeException
& )
481 catch ( lang::IllegalArgumentException
& )
490 bool ContentProviderImplHelper::removeAdditionalPropertySet(
491 const OUString
& rKey
, bool bRecursive
)
493 osl::MutexGuard
aGuard( m_aMutex
);
497 // Get propertyset registry.
498 getAdditionalPropertySetRegistry();
500 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
502 uno::Reference
< container::XNameAccess
> xNameAccess(
503 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
504 if ( xNameAccess
.is() )
506 uno::Sequence
< OUString
> aKeys
507 = xNameAccess
->getElementNames();
508 sal_Int32 nCount
= aKeys
.getLength();
511 OUString aKeyWithSlash
= rKey
;
512 OUString aKeyWithoutSlash
;
513 if ( !aKeyWithSlash
.endsWith("/") )
515 aKeyWithSlash
+= "/";
516 aKeyWithoutSlash
= rKey
;
518 else if ( !rKey
.isEmpty() )
520 = rKey
.copy( 0, rKey
.getLength() - 1 );
522 const OUString
* pKeys
= aKeys
.getConstArray();
523 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
525 const OUString
& rCurrKey
= pKeys
[ n
];
526 if ( rCurrKey
.startsWith(aKeyWithSlash
)
527 || rCurrKey
== aKeyWithoutSlash
)
529 if ( !removeAdditionalPropertySet(
544 // Get propertyset registry.
545 getAdditionalPropertySetRegistry();
547 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
548 m_pImpl
->m_xPropertySetRegistry
->removePropertySet( rKey
);
555 } // namespace ucbhelper
557 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */