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/providerhelper.hxx>
34 #include <ucbhelper/macros.hxx>
36 #include <osl/diagnose.h>
37 #include <osl/mutex.hxx>
38 #include <cppuhelper/weakref.hxx>
40 #include <unordered_map>
42 using namespace com::sun::star
;
44 namespace ucbhelper_impl
47 typedef std::unordered_map
50 uno::WeakReference
< ucb::XContent
>
54 struct ContentProviderImplHelper_Impl
56 uno::Reference
< css::ucb::XPropertySetRegistry
> m_xPropertySetRegistry
;
60 } // namespace ucbhelper_impl
64 ContentProviderImplHelper::ContentProviderImplHelper(
65 const uno::Reference
< uno::XComponentContext
>& rxContext
)
66 : m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl
),
67 m_xContext( rxContext
)
72 ContentProviderImplHelper::~ContentProviderImplHelper()
77 sal_Bool SAL_CALL
ContentProviderImplHelper::supportsService(
78 const OUString
& ServiceName
)
80 return cppu::supportsService(this, ServiceName
);
84 sal_Int32 SAL_CALL
ContentProviderImplHelper::compareContentIds(
85 const uno::Reference
< css::ucb::XContentIdentifier
>& Id1
,
86 const uno::Reference
< css::ucb::XContentIdentifier
>& Id2
)
88 // Simply do a string compare.
90 OUString
aURL1( Id1
->getContentIdentifier() );
91 OUString
aURL2( Id2
->getContentIdentifier() );
93 return aURL1
.compareTo( aURL2
);
96 void ContentProviderImplHelper::cleanupRegisteredContents()
98 osl::MutexGuard
aGuard( m_aMutex
);
100 ucbhelper_impl::Contents::iterator it
101 = m_pImpl
->m_aContents
.begin();
102 while( it
!= m_pImpl
->m_aContents
.end() )
104 uno::Reference
< ucb::XContent
> xContent( (*it
).second
);
105 if ( !xContent
.is() )
107 ucbhelper_impl::Contents::iterator tmp
= it
;
109 m_pImpl
->m_aContents
.erase( tmp
);
118 void ContentProviderImplHelper::removeContent( ContentImplHelper
* pContent
)
120 osl::MutexGuard
aGuard( m_aMutex
);
122 cleanupRegisteredContents();
125 pContent
->getIdentifier()->getContentIdentifier() );
127 ucbhelper_impl::Contents::iterator it
= m_pImpl
->m_aContents
.find( aURL
);
129 if ( it
!= m_pImpl
->m_aContents
.end() )
130 m_pImpl
->m_aContents
.erase( it
);
133 rtl::Reference
< ContentImplHelper
>
134 ContentProviderImplHelper::queryExistingContent(
135 const uno::Reference
< css::ucb::XContentIdentifier
>& Identifier
)
137 return queryExistingContent( Identifier
->getContentIdentifier() );
140 rtl::Reference
< ContentImplHelper
>
141 ContentProviderImplHelper::queryExistingContent( const OUString
& rURL
)
143 osl::MutexGuard
aGuard( m_aMutex
);
145 cleanupRegisteredContents();
147 // Check, if a content with given id already exists...
149 ucbhelper_impl::Contents::const_iterator it
150 = m_pImpl
->m_aContents
.find( rURL
);
151 if ( it
!= m_pImpl
->m_aContents
.end() )
153 uno::Reference
< ucb::XContent
> xContent( (*it
).second
);
156 return rtl::Reference
< ContentImplHelper
>(
157 static_cast< ContentImplHelper
* >( xContent
.get() ) );
160 return rtl::Reference
< ContentImplHelper
>();
163 void ContentProviderImplHelper::queryExistingContents(
164 ContentRefList
& rContents
)
166 osl::MutexGuard
aGuard( m_aMutex
);
168 cleanupRegisteredContents();
170 for ( const auto& rContent
: m_pImpl
->m_aContents
)
172 uno::Reference
< ucb::XContent
> xContent( rContent
.second
);
175 rContents
.emplace_back(
176 static_cast< ContentImplHelper
* >( xContent
.get() ) );
181 void ContentProviderImplHelper::registerNewContent(
182 const uno::Reference
< ucb::XContent
> & xContent
)
184 if ( !xContent
.is() )
187 osl::MutexGuard
aGuard( m_aMutex
);
189 cleanupRegisteredContents();
192 xContent
->getIdentifier()->getContentIdentifier() );
193 ucbhelper_impl::Contents::const_iterator it
194 = m_pImpl
->m_aContents
.find( aURL
);
195 if ( it
== m_pImpl
->m_aContents
.end() )
196 m_pImpl
->m_aContents
[ aURL
] = xContent
;
199 uno::Reference
< css::ucb::XPropertySetRegistry
>
200 ContentProviderImplHelper::getAdditionalPropertySetRegistry()
202 // Get propertyset registry.
204 osl::MutexGuard
aGuard( m_aMutex
);
206 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
208 uno::Reference
< css::ucb::XPropertySetRegistryFactory
>
209 xRegFac
= css::ucb::Store::create( m_xContext
);
211 // Open/create a registry.
212 m_pImpl
->m_xPropertySetRegistry
213 = xRegFac
->createPropertySetRegistry( OUString() );
215 OSL_ENSURE( m_pImpl
->m_xPropertySetRegistry
.is(),
216 "ContentProviderImplHelper::getAdditionalPropertySet - "
217 "Error opening registry!" );
220 return m_pImpl
->m_xPropertySetRegistry
;
223 uno::Reference
< css::ucb::XPersistentPropertySet
>
224 ContentProviderImplHelper::getAdditionalPropertySet(
225 const OUString
& rKey
, bool bCreate
)
227 // Get propertyset registry.
228 getAdditionalPropertySetRegistry();
230 if ( m_pImpl
->m_xPropertySetRegistry
.is() )
232 // Open/create persistent property set.
233 return m_pImpl
->m_xPropertySetRegistry
->openPropertySet(
237 return uno::Reference
< css::ucb::XPersistentPropertySet
>();
240 bool ContentProviderImplHelper::renameAdditionalPropertySet(
241 const OUString
& rOldKey
,
242 const OUString
& rNewKey
,
245 if ( rOldKey
== rNewKey
)
248 osl::MutexGuard
aGuard( m_aMutex
);
252 // Get propertyset registry.
253 getAdditionalPropertySetRegistry();
255 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
258 uno::Reference
< container::XNameAccess
> xNameAccess(
259 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
260 if ( !xNameAccess
.is() )
263 const uno::Sequence
< OUString
> aKeys
264 = xNameAccess
->getElementNames();
265 if ( aKeys
.hasElements() )
267 OUString aOldKeyWithSlash
= rOldKey
;
268 OUString aOldKeyWithoutSlash
;
269 if ( !aOldKeyWithSlash
.endsWith("/") )
271 aOldKeyWithSlash
+= "/";
272 aOldKeyWithoutSlash
= rOldKey
;
274 else if ( !rOldKey
.isEmpty() )
276 = rOldKey
.copy( 0, rOldKey
.getLength() - 1 );
278 for ( const OUString
& rKey
: aKeys
)
280 if ( rKey
.startsWith( aOldKeyWithSlash
)
281 || rKey
== aOldKeyWithoutSlash
)
285 0, rOldKey
.getLength(), rNewKey
);
286 if ( !renameAdditionalPropertySet(
287 rKey
, aNewKey
, false ) )
295 // Get old property set, if exists.
296 uno::Reference
< css::ucb::XPersistentPropertySet
> xOldSet
297 = getAdditionalPropertySet( rOldKey
, false );
300 // Rename property set.
301 uno::Reference
< container::XNamed
> xNamed(
302 xOldSet
, uno::UNO_QUERY
);
306 // ??? throws no exceptions and has no return value ???
307 xNamed
->setName( rNewKey
);
313 bool ContentProviderImplHelper::copyAdditionalPropertySet(
314 const OUString
& rSourceKey
,
315 const OUString
& rTargetKey
,
318 if ( rSourceKey
== rTargetKey
)
321 osl::MutexGuard
aGuard( m_aMutex
);
325 // Get propertyset registry.
326 getAdditionalPropertySetRegistry();
328 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
331 uno::Reference
< container::XNameAccess
> xNameAccess(
332 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
333 if ( !xNameAccess
.is() )
336 const uno::Sequence
< OUString
> aKeys
337 = xNameAccess
->getElementNames();
338 if ( aKeys
.hasElements() )
340 OUString aSrcKeyWithSlash
= rSourceKey
;
341 OUString aSrcKeyWithoutSlash
;
342 if ( !aSrcKeyWithSlash
.endsWith("/") )
344 aSrcKeyWithSlash
+= "/";
345 aSrcKeyWithoutSlash
= rSourceKey
;
347 else if ( !rSourceKey
.isEmpty() )
348 aSrcKeyWithoutSlash
= rSourceKey
.copy(
349 0, rSourceKey
.getLength() - 1 );
351 for ( const OUString
& rKey
: aKeys
)
353 if ( rKey
.startsWith(aSrcKeyWithSlash
)
354 || rKey
== aSrcKeyWithoutSlash
)
358 0, rSourceKey
.getLength(), rTargetKey
);
359 if ( !copyAdditionalPropertySet(
360 rKey
, aNewKey
, false ) )
368 // Get old property set, if exists.
369 uno::Reference
< css::ucb::XPersistentPropertySet
>
370 xOldPropSet
= getAdditionalPropertySet( rSourceKey
, false );
371 if ( !xOldPropSet
.is() )
374 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
375 = xOldPropSet
->getPropertySetInfo();
376 if ( !xPropSetInfo
.is() )
379 uno::Reference
< beans::XPropertyAccess
> xOldPropAccess(
380 xOldPropSet
, uno::UNO_QUERY
);
381 if ( !xOldPropAccess
.is() )
384 // Obtain all values from old set.
385 const uno::Sequence
< beans::PropertyValue
> aValues
386 = xOldPropAccess
->getPropertyValues();
388 uno::Sequence
< beans::Property
> aProps
389 = xPropSetInfo
->getProperties();
391 if ( aValues
.hasElements() )
393 // Fail, if property set with new key already exists.
394 uno::Reference
< css::ucb::XPersistentPropertySet
>
396 = getAdditionalPropertySet( rTargetKey
, false );
397 if ( xNewPropSet
.is() )
400 // Create new, empty set.
401 xNewPropSet
= getAdditionalPropertySet( rTargetKey
, true );
402 if ( !xNewPropSet
.is() )
405 uno::Reference
< beans::XPropertyContainer
> xNewPropContainer(
406 xNewPropSet
, uno::UNO_QUERY
);
407 if ( !xNewPropContainer
.is() )
410 for ( const beans::PropertyValue
& rValue
: aValues
)
412 sal_Int16 nAttribs
= 0;
413 auto pProp
= std::find_if(aProps
.begin(), aProps
.end(),
414 [&rValue
](const beans::Property
& rProp
) { return rProp
.Name
== rValue
.Name
; });
415 if (pProp
!= aProps
.end())
416 nAttribs
= pProp
->Attributes
;
420 xNewPropContainer
->addProperty(
421 rValue
.Name
, nAttribs
, rValue
.Value
);
423 catch ( beans::PropertyExistException
& )
426 catch ( beans::IllegalTypeException
& )
429 catch ( lang::IllegalArgumentException
& )
438 bool ContentProviderImplHelper::removeAdditionalPropertySet(
439 const OUString
& rKey
, bool bRecursive
)
441 osl::MutexGuard
aGuard( m_aMutex
);
445 // Get propertyset registry.
446 getAdditionalPropertySetRegistry();
448 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
451 uno::Reference
< container::XNameAccess
> xNameAccess(
452 m_pImpl
->m_xPropertySetRegistry
, uno::UNO_QUERY
);
453 if ( !xNameAccess
.is() )
456 const uno::Sequence
< OUString
> aKeys
457 = xNameAccess
->getElementNames();
458 if ( aKeys
.hasElements() )
460 OUString aKeyWithSlash
= rKey
;
461 OUString aKeyWithoutSlash
;
462 if ( !aKeyWithSlash
.endsWith("/") )
464 aKeyWithSlash
+= "/";
465 aKeyWithoutSlash
= rKey
;
467 else if ( !rKey
.isEmpty() )
469 = rKey
.copy( 0, rKey
.getLength() - 1 );
471 for ( const OUString
& rCurrKey
: aKeys
)
473 if ( rCurrKey
.startsWith(aKeyWithSlash
)
474 || rCurrKey
== aKeyWithoutSlash
)
476 if ( !removeAdditionalPropertySet(
485 // Get propertyset registry.
486 getAdditionalPropertySetRegistry();
488 if ( !m_pImpl
->m_xPropertySetRegistry
.is() )
491 m_pImpl
->m_xPropertySetRegistry
->removePropertySet( rKey
);
496 } // namespace ucbhelper
498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */