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 : #include <boost/unordered_map.hpp>
21 : #include <com/sun/star/beans/XPropertyAccess.hpp>
22 : #include <com/sun/star/container/XNameAccess.hpp>
23 : #include <com/sun/star/container/XNamed.hpp>
24 : #include <com/sun/star/ucb/Store.hpp>
25 : #include <com/sun/star/ucb/XPropertySetRegistry.hpp>
26 : #include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
27 : #include <cppuhelper/supportsservice.hxx>
28 : #include <ucbhelper/contenthelper.hxx>
29 : #include <ucbhelper/contentidentifier.hxx>
30 : #include <ucbhelper/providerhelper.hxx>
31 :
32 : #include "osl/diagnose.h"
33 : #include "osl/mutex.hxx"
34 : #include "cppuhelper/weakref.hxx"
35 :
36 : using namespace com::sun::star;
37 :
38 : namespace ucbhelper_impl
39 : {
40 :
41 : struct equalString
42 : {
43 0 : bool operator()(
44 : const OUString& rKey11, const OUString& rKey22 ) const
45 : {
46 0 : return !!( rKey11 == rKey22 );
47 : }
48 : };
49 :
50 : struct hashString
51 : {
52 0 : size_t operator()( const OUString & rName ) const
53 : {
54 0 : return rName.hashCode();
55 : }
56 : };
57 :
58 : typedef boost::unordered_map
59 : <
60 : OUString,
61 : uno::WeakReference< ucb::XContent >,
62 : hashString,
63 : equalString
64 : >
65 : Contents;
66 :
67 0 : struct ContentProviderImplHelper_Impl
68 : {
69 : uno::Reference< com::sun::star::ucb::XPropertySetRegistry >
70 : m_xPropertySetRegistry;
71 : Contents
72 : m_aContents;
73 : };
74 :
75 : } // namespace ucbhelper_impl
76 :
77 : namespace ucbhelper {
78 :
79 0 : ContentProviderImplHelper::ContentProviderImplHelper(
80 : const uno::Reference< uno::XComponentContext >& rxContext )
81 0 : : m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ),
82 0 : m_xContext( rxContext )
83 : {
84 0 : }
85 :
86 : // virtual
87 0 : ContentProviderImplHelper::~ContentProviderImplHelper()
88 : {
89 0 : delete m_pImpl;
90 0 : }
91 :
92 : // XInterface
93 0 : void SAL_CALL ContentProviderImplHelper::acquire()
94 : throw()
95 : {
96 0 : OWeakObject::acquire();
97 0 : }
98 :
99 0 : void SAL_CALL ContentProviderImplHelper::release()
100 : throw()
101 : {
102 0 : OWeakObject::release();
103 0 : }
104 :
105 0 : css::uno::Any SAL_CALL ContentProviderImplHelper::queryInterface( const css::uno::Type & rType )
106 : throw( css::uno::RuntimeException, std::exception )
107 : {
108 : css::uno::Any aRet = cppu::queryInterface( rType,
109 : (static_cast< lang::XTypeProvider* >(this)),
110 : (static_cast< lang::XServiceInfo* >(this)),
111 : (static_cast< css::ucb::XContentProvider* >(this))
112 0 : );
113 0 : return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
114 : }
115 :
116 0 : XTYPEPROVIDER_IMPL_3( ContentProviderImplHelper,
117 : lang::XTypeProvider,
118 : lang::XServiceInfo,
119 : com::sun::star::ucb::XContentProvider );
120 :
121 : // virtual
122 0 : sal_Bool SAL_CALL ContentProviderImplHelper::supportsService(
123 : const OUString& ServiceName )
124 : throw( uno::RuntimeException, std::exception )
125 : {
126 0 : return cppu::supportsService(this, ServiceName);
127 : }
128 :
129 : // virtual
130 0 : sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds(
131 : const uno::Reference< com::sun::star::ucb::XContentIdentifier >& Id1,
132 : const uno::Reference< com::sun::star::ucb::XContentIdentifier >& Id2 )
133 : throw( uno::RuntimeException, std::exception )
134 : {
135 : // Simply do a string compare.
136 :
137 0 : OUString aURL1( Id1->getContentIdentifier() );
138 0 : OUString aURL2( Id2->getContentIdentifier() );
139 :
140 0 : return aURL1.compareTo( aURL2 );
141 : }
142 :
143 0 : void ContentProviderImplHelper::cleanupRegisteredContents()
144 : {
145 0 : osl::MutexGuard aGuard( m_aMutex );
146 :
147 : ucbhelper_impl::Contents::iterator it
148 0 : = m_pImpl->m_aContents.begin();
149 0 : while( it != m_pImpl->m_aContents.end() )
150 : {
151 0 : uno::Reference< ucb::XContent > xContent( (*it).second );
152 0 : if ( !xContent.is() )
153 : {
154 0 : ucbhelper_impl::Contents::iterator tmp = it;
155 0 : ++it;
156 0 : m_pImpl->m_aContents.erase( tmp );
157 : }
158 : else
159 : {
160 0 : ++it;
161 : }
162 0 : }
163 0 : }
164 :
165 0 : void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent )
166 : {
167 0 : osl::MutexGuard aGuard( m_aMutex );
168 :
169 0 : cleanupRegisteredContents();
170 :
171 : const OUString aURL(
172 0 : pContent->getIdentifier()->getContentIdentifier() );
173 :
174 0 : ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL );
175 :
176 0 : if ( it != m_pImpl->m_aContents.end() )
177 0 : m_pImpl->m_aContents.erase( it );
178 0 : }
179 :
180 : rtl::Reference< ContentImplHelper >
181 0 : ContentProviderImplHelper::queryExistingContent(
182 : const uno::Reference< com::sun::star::ucb::XContentIdentifier >&
183 : Identifier )
184 : {
185 0 : return queryExistingContent( Identifier->getContentIdentifier() );
186 : }
187 :
188 : rtl::Reference< ContentImplHelper >
189 0 : ContentProviderImplHelper::queryExistingContent( const OUString& rURL )
190 : {
191 0 : osl::MutexGuard aGuard( m_aMutex );
192 :
193 0 : cleanupRegisteredContents();
194 :
195 : // Check, if a content with given id already exists...
196 :
197 : ucbhelper_impl::Contents::const_iterator it
198 0 : = m_pImpl->m_aContents.find( rURL );
199 0 : if ( it != m_pImpl->m_aContents.end() )
200 : {
201 0 : uno::Reference< ucb::XContent > xContent( (*it).second );
202 0 : if ( xContent.is() )
203 : {
204 : return rtl::Reference< ContentImplHelper >(
205 0 : static_cast< ContentImplHelper * >( xContent.get() ) );
206 0 : }
207 : }
208 0 : return rtl::Reference< ContentImplHelper >();
209 : }
210 :
211 0 : void ContentProviderImplHelper::queryExistingContents(
212 : ContentRefList& rContents )
213 : {
214 0 : osl::MutexGuard aGuard( m_aMutex );
215 :
216 0 : cleanupRegisteredContents();
217 :
218 : ucbhelper_impl::Contents::const_iterator it
219 0 : = m_pImpl->m_aContents.begin();
220 : ucbhelper_impl::Contents::const_iterator end
221 0 : = m_pImpl->m_aContents.end();
222 :
223 0 : while ( it != end )
224 : {
225 0 : uno::Reference< ucb::XContent > xContent( (*it).second );
226 0 : if ( xContent.is() )
227 : {
228 : rContents.push_back(
229 : rtl::Reference< ContentImplHelper >(
230 0 : static_cast< ContentImplHelper * >( xContent.get() ) ) );
231 : }
232 0 : ++it;
233 0 : }
234 0 : }
235 :
236 0 : void ContentProviderImplHelper::registerNewContent(
237 : const uno::Reference< ucb::XContent > & xContent )
238 : {
239 0 : if ( xContent.is() )
240 : {
241 0 : osl::MutexGuard aGuard( m_aMutex );
242 :
243 0 : cleanupRegisteredContents();
244 :
245 : const OUString aURL(
246 0 : xContent->getIdentifier()->getContentIdentifier() );
247 : ucbhelper_impl::Contents::const_iterator it
248 0 : = m_pImpl->m_aContents.find( aURL );
249 0 : if ( it == m_pImpl->m_aContents.end() )
250 0 : m_pImpl->m_aContents[ aURL ] = xContent;
251 : }
252 0 : }
253 :
254 : uno::Reference< com::sun::star::ucb::XPropertySetRegistry >
255 0 : ContentProviderImplHelper::getAdditionalPropertySetRegistry()
256 : {
257 : // Get propertyset registry.
258 :
259 0 : osl::MutexGuard aGuard( m_aMutex );
260 :
261 0 : if ( !m_pImpl->m_xPropertySetRegistry.is() )
262 : {
263 : uno::Reference< com::sun::star::ucb::XPropertySetRegistryFactory >
264 0 : xRegFac = com::sun::star::ucb::Store::create( m_xContext );
265 :
266 : // Open/create a registry.
267 : m_pImpl->m_xPropertySetRegistry
268 0 : = xRegFac->createPropertySetRegistry( OUString() );
269 :
270 : OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(),
271 : "ContentProviderImplHelper::getAdditionalPropertySet - "
272 0 : "Error opening registry!" );
273 : }
274 :
275 0 : return m_pImpl->m_xPropertySetRegistry;
276 : }
277 :
278 : uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
279 0 : ContentProviderImplHelper::getAdditionalPropertySet(
280 : const OUString& rKey, bool bCreate )
281 : {
282 : // Get propertyset registry.
283 0 : getAdditionalPropertySetRegistry();
284 :
285 0 : if ( m_pImpl->m_xPropertySetRegistry.is() )
286 : {
287 : // Open/create persistent property set.
288 : return uno::Reference< com::sun::star::ucb::XPersistentPropertySet >(
289 0 : m_pImpl->m_xPropertySetRegistry->openPropertySet(
290 0 : rKey, bCreate ) );
291 : }
292 :
293 0 : return uno::Reference< com::sun::star::ucb::XPersistentPropertySet >();
294 : }
295 :
296 0 : bool ContentProviderImplHelper::renameAdditionalPropertySet(
297 : const OUString& rOldKey,
298 : const OUString& rNewKey,
299 : bool bRecursive )
300 : {
301 0 : if ( rOldKey == rNewKey )
302 0 : return true;
303 :
304 0 : osl::MutexGuard aGuard( m_aMutex );
305 :
306 0 : if ( bRecursive )
307 : {
308 : // Get propertyset registry.
309 0 : getAdditionalPropertySetRegistry();
310 :
311 0 : if ( m_pImpl->m_xPropertySetRegistry.is() )
312 : {
313 : uno::Reference< container::XNameAccess > xNameAccess(
314 0 : m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
315 0 : if ( xNameAccess.is() )
316 : {
317 : uno::Sequence< OUString > aKeys
318 0 : = xNameAccess->getElementNames();
319 0 : sal_Int32 nCount = aKeys.getLength();
320 0 : if ( nCount > 0 )
321 : {
322 0 : OUString aOldKeyWithSlash = rOldKey;
323 0 : OUString aOldKeyWithoutSlash;
324 0 : if ( !aOldKeyWithSlash.endsWith("/") )
325 : {
326 0 : aOldKeyWithSlash += OUString( '/' );
327 0 : aOldKeyWithoutSlash = rOldKey;
328 : }
329 0 : else if ( !rOldKey.isEmpty() )
330 : aOldKeyWithoutSlash
331 0 : = rOldKey.copy( 0, rOldKey.getLength() - 1 );
332 :
333 0 : const OUString* pKeys = aKeys.getConstArray();
334 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
335 : {
336 0 : const OUString& rKey = pKeys[ n ];
337 0 : if ( rKey.compareTo(
338 : aOldKeyWithSlash,
339 0 : aOldKeyWithSlash.getLength() ) == 0
340 0 : || rKey.equals( aOldKeyWithoutSlash ) )
341 : {
342 : OUString aNewKey
343 : = rKey.replaceAt(
344 0 : 0, rOldKey.getLength(), rNewKey );
345 0 : if ( !renameAdditionalPropertySet(
346 0 : rKey, aNewKey, false ) )
347 0 : return false;
348 : }
349 0 : }
350 0 : }
351 : }
352 : else
353 0 : return false;
354 : }
355 : else
356 0 : return false;
357 : }
358 : else
359 : {
360 : // Get old property set, if exists.
361 : uno::Reference< com::sun::star::ucb::XPersistentPropertySet > xOldSet
362 0 : = getAdditionalPropertySet( rOldKey, false );
363 0 : if ( xOldSet.is() )
364 : {
365 : // Rename property set.
366 : uno::Reference< container::XNamed > xNamed(
367 0 : xOldSet, uno::UNO_QUERY );
368 0 : if ( xNamed.is() )
369 : {
370 : // ??? throws no exceptions and has no return value ???
371 0 : xNamed->setName( rNewKey );
372 : }
373 : else
374 0 : return false;
375 0 : }
376 : }
377 0 : return true;
378 : }
379 :
380 0 : bool ContentProviderImplHelper::copyAdditionalPropertySet(
381 : const OUString& rSourceKey,
382 : const OUString& rTargetKey,
383 : bool bRecursive )
384 : {
385 0 : if ( rSourceKey == rTargetKey )
386 0 : return true;
387 :
388 0 : osl::MutexGuard aGuard( m_aMutex );
389 :
390 0 : if ( bRecursive )
391 : {
392 : // Get propertyset registry.
393 0 : getAdditionalPropertySetRegistry();
394 :
395 0 : if ( m_pImpl->m_xPropertySetRegistry.is() )
396 : {
397 : uno::Reference< container::XNameAccess > xNameAccess(
398 0 : m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
399 0 : if ( xNameAccess.is() )
400 : {
401 : uno::Sequence< OUString > aKeys
402 0 : = xNameAccess->getElementNames();
403 0 : sal_Int32 nCount = aKeys.getLength();
404 0 : if ( nCount > 0 )
405 : {
406 0 : OUString aSrcKeyWithSlash = rSourceKey;
407 0 : OUString aSrcKeyWithoutSlash;
408 0 : if ( !aSrcKeyWithSlash.endsWith("/") )
409 : {
410 0 : aSrcKeyWithSlash += OUString( '/' );
411 0 : aSrcKeyWithoutSlash = rSourceKey;
412 : }
413 0 : else if ( !rSourceKey.isEmpty() )
414 0 : aSrcKeyWithoutSlash = rSourceKey.copy(
415 0 : 0, rSourceKey.getLength() - 1 );
416 :
417 0 : const OUString* pKeys = aKeys.getConstArray();
418 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
419 : {
420 0 : const OUString& rKey = pKeys[ n ];
421 0 : if ( rKey.compareTo(
422 : aSrcKeyWithSlash,
423 0 : aSrcKeyWithSlash.getLength() ) == 0
424 0 : || rKey.equals( aSrcKeyWithoutSlash ) )
425 : {
426 : OUString aNewKey
427 : = rKey.replaceAt(
428 0 : 0, rSourceKey.getLength(), rTargetKey );
429 0 : if ( !copyAdditionalPropertySet(
430 0 : rKey, aNewKey, false ) )
431 0 : return false;
432 : }
433 0 : }
434 0 : }
435 : }
436 : else
437 0 : return false;
438 : }
439 : else
440 0 : return false;
441 : }
442 : else
443 : {
444 : // Get old property set, if exists.
445 : uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
446 0 : xOldPropSet = getAdditionalPropertySet( rSourceKey, false );
447 0 : if ( !xOldPropSet.is() )
448 0 : return false;
449 :
450 : uno::Reference< beans::XPropertySetInfo > xPropSetInfo
451 0 : = xOldPropSet->getPropertySetInfo();
452 0 : if ( !xPropSetInfo.is() )
453 0 : return false;
454 :
455 : uno::Reference< beans::XPropertyAccess > xOldPropAccess(
456 0 : xOldPropSet, uno::UNO_QUERY );
457 0 : if ( !xOldPropAccess.is() )
458 0 : return false;
459 :
460 : // Obtain all values from old set.
461 : uno::Sequence< beans::PropertyValue > aValues
462 0 : = xOldPropAccess->getPropertyValues();
463 0 : sal_Int32 nCount = aValues.getLength();
464 :
465 : uno::Sequence< beans::Property > aProps
466 0 : = xPropSetInfo->getProperties();
467 :
468 0 : if ( nCount )
469 : {
470 : // Fail, if property set with new key already exists.
471 : uno::Reference< com::sun::star::ucb::XPersistentPropertySet >
472 : xNewPropSet
473 0 : = getAdditionalPropertySet( rTargetKey, false );
474 0 : if ( xNewPropSet.is() )
475 0 : return false;
476 :
477 : // Create new, empty set.
478 0 : xNewPropSet = getAdditionalPropertySet( rTargetKey, true );
479 0 : if ( !xNewPropSet.is() )
480 0 : return false;
481 :
482 : uno::Reference< beans::XPropertyContainer > xNewPropContainer(
483 0 : xNewPropSet, uno::UNO_QUERY );
484 0 : if ( !xNewPropContainer.is() )
485 0 : return false;
486 :
487 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
488 : {
489 0 : const beans::PropertyValue& rValue = aValues[ n ];
490 :
491 0 : sal_Int16 nAttribs = 0;
492 0 : for ( sal_Int32 m = 0; m < aProps.getLength(); ++m )
493 : {
494 0 : if ( aProps[ m ].Name == rValue.Name )
495 : {
496 0 : nAttribs = aProps[ m ].Attributes;
497 0 : break;
498 : }
499 : }
500 :
501 : try
502 : {
503 0 : xNewPropContainer->addProperty(
504 0 : rValue.Name, nAttribs, rValue.Value );
505 : }
506 0 : catch ( beans::PropertyExistException & )
507 : {
508 : }
509 0 : catch ( beans::IllegalTypeException & )
510 : {
511 : }
512 0 : catch ( lang::IllegalArgumentException & )
513 : {
514 : }
515 0 : }
516 0 : }
517 : }
518 0 : return true;
519 : }
520 :
521 0 : bool ContentProviderImplHelper::removeAdditionalPropertySet(
522 : const OUString& rKey, bool bRecursive )
523 : {
524 0 : osl::MutexGuard aGuard( m_aMutex );
525 :
526 0 : if ( bRecursive )
527 : {
528 : // Get propertyset registry.
529 0 : getAdditionalPropertySetRegistry();
530 :
531 0 : if ( m_pImpl->m_xPropertySetRegistry.is() )
532 : {
533 : uno::Reference< container::XNameAccess > xNameAccess(
534 0 : m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
535 0 : if ( xNameAccess.is() )
536 : {
537 : uno::Sequence< OUString > aKeys
538 0 : = xNameAccess->getElementNames();
539 0 : sal_Int32 nCount = aKeys.getLength();
540 0 : if ( nCount > 0 )
541 : {
542 0 : OUString aKeyWithSlash = rKey;
543 0 : OUString aKeyWithoutSlash;
544 0 : if ( !aKeyWithSlash.endsWith("/") )
545 : {
546 0 : aKeyWithSlash += OUString( '/' );
547 0 : aKeyWithoutSlash = rKey;
548 : }
549 0 : else if ( !rKey.isEmpty() )
550 : aKeyWithoutSlash
551 0 : = rKey.copy( 0, rKey.getLength() - 1 );
552 :
553 0 : const OUString* pKeys = aKeys.getConstArray();
554 0 : for ( sal_Int32 n = 0; n < nCount; ++n )
555 : {
556 0 : const OUString& rCurrKey = pKeys[ n ];
557 0 : if ( rCurrKey.compareTo(
558 : aKeyWithSlash,
559 0 : aKeyWithSlash.getLength() ) == 0
560 0 : || rCurrKey.equals( aKeyWithoutSlash ) )
561 : {
562 0 : if ( !removeAdditionalPropertySet(
563 0 : rCurrKey, false ) )
564 0 : return false;
565 : }
566 0 : }
567 0 : }
568 : }
569 : else
570 0 : return false;
571 : }
572 : else
573 0 : return false;
574 : }
575 : else
576 : {
577 : // Get propertyset registry.
578 0 : getAdditionalPropertySetRegistry();
579 :
580 0 : if ( m_pImpl->m_xPropertySetRegistry.is() )
581 0 : m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey );
582 : else
583 0 : return false;
584 : }
585 0 : return true;
586 : }
587 :
588 : } // namespace ucbhelper
589 :
590 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|