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 "basecontainer.hxx"
22 : #include "constant.hxx"
23 :
24 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
25 : #include <com/sun/star/document/FilterConfigRefresh.hpp>
26 : #include <com/sun/star/uno/Type.h>
27 : #include <comphelper/enumhelper.hxx>
28 : #include <comphelper/sequence.hxx>
29 : #include <cppuhelper/supportsservice.hxx>
30 : #include <osl/diagnose.h>
31 : #include <rtl/instance.hxx>
32 :
33 : #define LOAD_IMPLICIT
34 :
35 : namespace filter{
36 : namespace config{
37 :
38 :
39 : namespace
40 : {
41 : typedef ::salhelper::SingletonRef< FilterCache > FilterCacheRefHold;
42 : /** @short hold at least one filter cache instance alive and
43 : prevent the office from unloading this cache if no filter
44 : is currently used.*/
45 : struct thePerformanceOptimizer :
46 : public rtl::Static<FilterCacheRefHold, thePerformanceOptimizer>
47 : {
48 : };
49 : }
50 :
51 123045 : BaseContainer::BaseContainer()
52 : : BaseLock ( )
53 : , m_rCache ( )
54 : , m_pFlushCache(NULL )
55 : , m_eType()
56 123045 : , m_lListener (m_aLock)
57 : {
58 123045 : m_rCache->load(FilterCache::E_CONTAINS_STANDARD);
59 123045 : thePerformanceOptimizer::get();
60 123045 : }
61 :
62 :
63 :
64 123045 : BaseContainer::~BaseContainer()
65 : {
66 123045 : }
67 :
68 :
69 :
70 123045 : void BaseContainer::init(const css::uno::Reference< css::uno::XComponentContext >& rxContext ,
71 : const OUString& sImplementationName,
72 : const css::uno::Sequence< OUString >& lServiceNames ,
73 : FilterCache::EItemType eType )
74 : {
75 : // SAFE ->
76 123045 : ::osl::ResettableMutexGuard aLock(m_aLock);
77 :
78 123045 : m_sImplementationName = sImplementationName;
79 123045 : m_lServiceNames = lServiceNames ;
80 123045 : m_eType = eType ;
81 123045 : m_xRefreshBroadcaster = css::document::FilterConfigRefresh::create(rxContext);
82 : // <- SAFE
83 123045 : }
84 :
85 :
86 :
87 77944 : void BaseContainer::impl_loadOnDemand()
88 : {
89 : #ifdef LOAD_IMPLICIT
90 : // SAFE ->
91 77944 : ::osl::ResettableMutexGuard aLock(m_aLock);
92 :
93 : // A generic container needs all items of a set of our cache!
94 : // Of course it can block for a while, till the cache is really filled.
95 : // Note: dont load all sets supported by the cache here!
96 :
97 77944 : FilterCache::EFillState eRequiredState = FilterCache::E_CONTAINS_NOTHING;
98 77944 : switch(m_eType)
99 : {
100 : case FilterCache::E_TYPE :
101 7989 : eRequiredState = FilterCache::E_CONTAINS_TYPES;
102 7989 : break;
103 :
104 : case FilterCache::E_FILTER :
105 19051 : eRequiredState = FilterCache::E_CONTAINS_FILTERS;
106 19051 : break;
107 :
108 : case FilterCache::E_FRAMELOADER :
109 29581 : eRequiredState = FilterCache::E_CONTAINS_FRAMELOADERS;
110 29581 : break;
111 :
112 : case FilterCache::E_CONTENTHANDLER :
113 21323 : eRequiredState = FilterCache::E_CONTAINS_CONTENTHANDLERS;
114 21323 : break;
115 : }
116 :
117 77944 : m_rCache->load(eRequiredState);
118 : // <- SAFE
119 : #endif
120 77944 : }
121 :
122 :
123 :
124 4 : void BaseContainer::impl_initFlushMode()
125 : throw (css::uno::RuntimeException)
126 : {
127 : // SAFE ->
128 4 : ::osl::ResettableMutexGuard aLock(m_aLock);
129 4 : if (!m_pFlushCache)
130 1 : m_pFlushCache = m_rCache->clone();
131 4 : if (!m_pFlushCache)
132 : throw css::uno::RuntimeException( "Can not create write copy of internal used cache on demand.",
133 0 : static_cast< OWeakObject* >(this));
134 : // <- SAFE
135 4 : }
136 :
137 :
138 :
139 77944 : FilterCache* BaseContainer::impl_getWorkingCache() const
140 : {
141 : // SAFE ->
142 77944 : ::osl::ResettableMutexGuard aLock(m_aLock);
143 77944 : if (m_pFlushCache)
144 8 : return m_pFlushCache;
145 : else
146 77936 : return &(*m_rCache);
147 : // <- SAFE
148 : }
149 :
150 :
151 :
152 7 : OUString SAL_CALL BaseContainer::getImplementationName()
153 : throw (css::uno::RuntimeException, std::exception)
154 : {
155 : // SAFE ->
156 7 : ::osl::ResettableMutexGuard aLock(m_aLock);
157 7 : return m_sImplementationName;
158 : // <- SAFE
159 : }
160 :
161 :
162 :
163 0 : sal_Bool SAL_CALL BaseContainer::supportsService(const OUString& sServiceName)
164 : throw (css::uno::RuntimeException, std::exception)
165 : {
166 0 : return cppu::supportsService(this, sServiceName);
167 : }
168 :
169 4 : css::uno::Sequence< OUString > SAL_CALL BaseContainer::getSupportedServiceNames()
170 : throw (css::uno::RuntimeException, std::exception)
171 : {
172 : // SAFE ->
173 4 : ::osl::ResettableMutexGuard aLock(m_aLock);
174 4 : return m_lServiceNames;
175 : // <- SAFE
176 : }
177 :
178 :
179 :
180 3 : void SAL_CALL BaseContainer::insertByName(const OUString& sItem ,
181 : const css::uno::Any& aValue)
182 : throw (css::lang::IllegalArgumentException ,
183 : css::container::ElementExistException,
184 : css::lang::WrappedTargetException ,
185 : css::uno::RuntimeException, std::exception )
186 : {
187 3 : if (sItem.isEmpty())
188 : throw css::lang::IllegalArgumentException("empty value not allowed as item name.",
189 : static_cast< css::container::XNameContainer* >(this),
190 0 : 1);
191 :
192 3 : CacheItem aItem;
193 : try
194 : {
195 3 : aItem << aValue;
196 : }
197 1 : catch(const css::uno::Exception& ex)
198 : {
199 1 : throw css::lang::IllegalArgumentException(ex.Message, static_cast< css::container::XNameContainer* >(this), 2);
200 : }
201 :
202 2 : impl_loadOnDemand();
203 :
204 : // SAFE -> ----------------------------------
205 4 : ::osl::ResettableMutexGuard aLock(m_aLock);
206 :
207 : // create write copy of used cache on demand ...
208 2 : impl_initFlushMode();
209 :
210 2 : FilterCache* pCache = impl_getWorkingCache();
211 2 : if (pCache->hasItem(m_eType, sItem))
212 1 : throw css::container::ElementExistException(OUString(), static_cast< css::container::XNameContainer* >(this));
213 1 : pCache->setItem(m_eType, sItem, aItem);
214 :
215 4 : aLock.clear();
216 : // <- SAFE ----------------------------------
217 1 : }
218 :
219 :
220 :
221 2 : void SAL_CALL BaseContainer::removeByName(const OUString& sItem)
222 : throw (css::container::NoSuchElementException,
223 : css::lang::WrappedTargetException ,
224 : css::uno::RuntimeException, std::exception )
225 : {
226 2 : impl_loadOnDemand();
227 :
228 : // SAFE -> ----------------------------------
229 2 : ::osl::ResettableMutexGuard aLock(m_aLock);
230 :
231 : // create write copy of used cache on demand ...
232 2 : impl_initFlushMode();
233 :
234 2 : FilterCache* pCache = impl_getWorkingCache();
235 2 : pCache->removeItem(m_eType, sItem); // throw exceptions automatically
236 :
237 2 : aLock.clear();
238 : // <- SAFE ----------------------------------
239 1 : }
240 :
241 :
242 :
243 0 : void SAL_CALL BaseContainer::replaceByName(const OUString& sItem ,
244 : const css::uno::Any& aValue)
245 : throw (css::lang::IllegalArgumentException ,
246 : css::container::NoSuchElementException,
247 : css::lang::WrappedTargetException ,
248 : css::uno::RuntimeException, std::exception )
249 : {
250 0 : if (sItem.isEmpty())
251 : throw css::lang::IllegalArgumentException("empty value not allowed as item name.",
252 : static_cast< css::container::XNameContainer* >(this),
253 0 : 1);
254 :
255 0 : CacheItem aItem;
256 : try
257 : {
258 0 : aItem << aValue;
259 : }
260 0 : catch(const css::uno::Exception& ex)
261 : {
262 0 : throw css::lang::IllegalArgumentException(ex.Message, static_cast< css::container::XNameContainer* >(this), 2);
263 : }
264 :
265 0 : impl_loadOnDemand();
266 :
267 : // SAFE -> ----------------------------------
268 0 : ::osl::ResettableMutexGuard aLock(m_aLock);
269 :
270 : // create write copy of used cache on demand ...
271 0 : impl_initFlushMode();
272 :
273 0 : FilterCache* pCache = impl_getWorkingCache();
274 0 : if (!pCache->hasItem(m_eType, sItem))
275 0 : throw css::container::NoSuchElementException(OUString(), static_cast< css::container::XNameContainer* >(this));
276 0 : pCache->setItem(m_eType, sItem, aItem);
277 :
278 0 : aLock.clear();
279 : // <- SAFE ----------------------------------
280 0 : }
281 :
282 :
283 :
284 25639 : css::uno::Any SAL_CALL BaseContainer::getByName(const OUString& sItem)
285 : throw (css::container::NoSuchElementException,
286 : css::lang::WrappedTargetException ,
287 : css::uno::RuntimeException, std::exception )
288 : {
289 25639 : if (sItem.isEmpty())
290 : throw css::container::NoSuchElementException( "An empty item can't be part of this cache!",
291 1708 : static_cast< css::container::XNameAccess* >(this));
292 :
293 23931 : css::uno::Any aValue;
294 :
295 23931 : impl_loadOnDemand();
296 :
297 : // SAFE ->
298 47862 : ::osl::ResettableMutexGuard aLock(m_aLock);
299 :
300 47862 : CacheItem aItem;
301 : try
302 : {
303 23931 : FilterCache* pCache = impl_getWorkingCache();
304 23931 : aItem = pCache->getItem(m_eType, sItem);
305 23916 : pCache->addStatePropsToItem(m_eType, sItem, aItem); // add implicit props "Finalized"/"Mandatory"
306 : }
307 15 : catch(const css::container::NoSuchElementException&)
308 : {
309 15 : throw;
310 : }
311 0 : catch(const css::uno::Exception&)
312 : {
313 : // TODO invalid cache!? How should it be handled right?
314 0 : aItem.clear();
315 : }
316 :
317 23916 : aValue <<= aItem.getAsPackedPropertyValueList();
318 : // <- SAFE
319 :
320 47832 : return aValue;
321 : }
322 :
323 :
324 :
325 26 : css::uno::Sequence< OUString > SAL_CALL BaseContainer::getElementNames()
326 : throw (css::uno::RuntimeException, std::exception)
327 : {
328 26 : css::uno::Sequence< OUString > lNames;
329 :
330 26 : impl_loadOnDemand();
331 :
332 : // SAFE ->
333 52 : ::osl::ResettableMutexGuard aLock(m_aLock);
334 :
335 : try
336 : {
337 26 : FilterCache* pCache = impl_getWorkingCache();
338 26 : OUStringList lKeys = pCache->getItemNames(m_eType);
339 26 : lNames = comphelper::containerToSequence(lKeys);
340 : }
341 0 : catch(const css::uno::Exception&)
342 : {
343 : // invalid cache!?
344 0 : lNames.realloc(0);
345 : }
346 :
347 : // <- SAFE
348 :
349 52 : return lNames;
350 : }
351 :
352 :
353 :
354 2858 : sal_Bool SAL_CALL BaseContainer::hasByName(const OUString& sItem)
355 : throw (css::uno::RuntimeException, std::exception)
356 : {
357 2858 : bool bHasOne = false;
358 :
359 2858 : impl_loadOnDemand();
360 :
361 : // SAFE ->
362 2858 : ::osl::ResettableMutexGuard aLock(m_aLock);
363 :
364 : try
365 : {
366 2858 : FilterCache* pCache = impl_getWorkingCache();
367 2858 : bHasOne = pCache->hasItem(m_eType, sItem);
368 : }
369 0 : catch(const css::uno::Exception&)
370 : {
371 : // invalid cache!?
372 0 : bHasOne = false;
373 : }
374 :
375 : // <- SAFE
376 :
377 2858 : return bHasOne;
378 : }
379 :
380 :
381 :
382 3 : css::uno::Type SAL_CALL BaseContainer::getElementType()
383 : throw (css::uno::RuntimeException, std::exception)
384 : {
385 : // no lock necessary - because the type of our items
386 : // is fix! no internal call or member needed ...
387 3 : return cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get();
388 : }
389 :
390 :
391 :
392 3 : sal_Bool SAL_CALL BaseContainer::hasElements()
393 : throw (css::uno::RuntimeException, std::exception)
394 : {
395 3 : bool bHasSome = false;
396 :
397 3 : impl_loadOnDemand();
398 :
399 : // SAFE ->
400 3 : ::osl::ResettableMutexGuard aLock(m_aLock);
401 :
402 : try
403 : {
404 3 : FilterCache* pCache = impl_getWorkingCache();
405 3 : bHasSome = pCache->hasItems(m_eType);
406 : }
407 0 : catch(const css::uno::Exception&)
408 : {
409 : // invalid cache?!
410 0 : bHasSome = false;
411 : }
412 :
413 : // <- SAFE
414 :
415 3 : return bHasSome;
416 : }
417 :
418 :
419 :
420 0 : css::uno::Reference< css::container::XEnumeration > SAL_CALL BaseContainer::createSubSetEnumerationByQuery(const OUString& /* sQuery */ )
421 : throw (css::uno::RuntimeException, std::exception)
422 : {
423 : OSL_FAIL("not pure virtual ... but not really implemented .-)");
424 :
425 0 : ::comphelper::OEnumerationByName* pEnum = new ::comphelper::OEnumerationByName(this, css::uno::Sequence< OUString >());
426 0 : return css::uno::Reference< css::container::XEnumeration >(static_cast< css::container::XEnumeration* >(pEnum), css::uno::UNO_QUERY);
427 : }
428 :
429 :
430 :
431 51122 : css::uno::Reference< css::container::XEnumeration > SAL_CALL BaseContainer::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties)
432 : throw (css::uno::RuntimeException, std::exception)
433 : {
434 51122 : css::uno::Reference< css::container::XEnumeration > xEnum;
435 102244 : OUStringList lKeys;
436 :
437 51122 : impl_loadOnDemand();
438 :
439 : // SAFE ->
440 102244 : ::osl::ResettableMutexGuard aLock(m_aLock);
441 :
442 : try
443 : {
444 : // convert the given properties first to our internal representation
445 51122 : CacheItem lProps;
446 51122 : lProps << lProperties;
447 :
448 : // search the key names of all items, where its properties match
449 : // the given ones in its minimum
450 51122 : FilterCache* pCache = impl_getWorkingCache();
451 51122 : lKeys = pCache->getMatchingItemsByProps(m_eType, lProps);
452 : }
453 0 : catch(const css::uno::Exception&)
454 : {
455 : // invalid cache, internal failure, wrong conversion ...!?
456 : // doesn't matter
457 0 : lKeys.clear();
458 : }
459 :
460 : // <- SAFE
461 :
462 : // create a specialized enumeration helper, which
463 : // provides the collected information outside.
464 : // It hold a reference to us ... and call our container interface directly.
465 : // be aware of some direct callbacks if it will be created :-)
466 :
467 : /* Note: Its not allowed to return NULL. Because an empty enumeration
468 : transport the same information but make no trouble outside.
469 : Further its easier to work directly with the return value
470 : instaed of checking of NULL returns! */
471 :
472 102244 : css::uno::Sequence< OUString > lSubSet = comphelper::containerToSequence(lKeys);
473 51122 : ::comphelper::OEnumerationByName* pEnum = new ::comphelper::OEnumerationByName(this, lSubSet);
474 102244 : return css::uno::Reference< css::container::XEnumeration >(static_cast< css::container::XEnumeration* >(pEnum), css::uno::UNO_QUERY);
475 : }
476 :
477 :
478 :
479 1 : void SAL_CALL BaseContainer::flush()
480 : throw (css::uno::RuntimeException, std::exception)
481 : {
482 : // SAFE ->
483 1 : ::osl::ResettableMutexGuard aLock(m_aLock);
484 :
485 1 : if (!m_pFlushCache)
486 : throw css::lang::WrappedTargetRuntimeException(
487 : "Can not guarantee cache consistency. Special flush container does not exists!",
488 : static_cast< OWeakObject* >(this),
489 0 : css::uno::Any());
490 :
491 : try
492 : {
493 1 : m_pFlushCache->flush();
494 : // Take over all changes into the global cache and
495 : // forget the clone.
496 : /* TODO
497 : -think about me
498 : If the global cache gets this information via listener,
499 : we should remove this method!
500 : */
501 1 : m_rCache->takeOver(*m_pFlushCache);
502 : }
503 0 : catch(const css::uno::Exception& ex)
504 : {
505 : // Dont remove the clone. May be the outside
506 : // user wish to repair it now and calls flush()
507 : // later again ...
508 :
509 : throw css::lang::WrappedTargetRuntimeException( "Flush rejected by internal container.",
510 : static_cast< OWeakObject* >(this),
511 0 : css::uno::makeAny(ex));
512 : }
513 :
514 1 : delete m_pFlushCache;
515 1 : m_pFlushCache = NULL;
516 :
517 2 : css::uno::Reference< css::util::XRefreshable > xRefreshBroadcaster = m_xRefreshBroadcaster;
518 :
519 1 : aLock.clear();
520 : // <- SAFE
521 :
522 1 : if (xRefreshBroadcaster.is())
523 1 : xRefreshBroadcaster->refresh();
524 :
525 : // notify listener outside the lock!
526 : // The used listener helper lives if we live
527 : // and is threadsafe by itself.
528 : // Further its not a good idea to hold the own lock
529 : // if an outside object is called :-)
530 2 : css::lang::EventObject aSource (static_cast< css::util::XFlushable* >(this));
531 1 : ::cppu::OInterfaceContainerHelper* pContainer = m_lListener.getContainer(cppu::UnoType<css::util::XFlushListener>::get());
532 1 : if (pContainer)
533 : {
534 1 : ::cppu::OInterfaceIteratorHelper pIterator(*pContainer);
535 3 : while (pIterator.hasMoreElements())
536 : {
537 : try
538 : {
539 : // ... this pointer can be interesting to find out, where will be called as listener
540 : // Dont optimize it to a direct iterator cast :-)
541 1 : css::util::XFlushListener* pListener = static_cast<css::util::XFlushListener*>(pIterator.next());
542 1 : pListener->flushed(aSource);
543 : }
544 0 : catch(const css::uno::Exception&)
545 : {
546 : // ignore any "damaged" flush listener!
547 : // May its remote reference is broken ...
548 0 : pIterator.remove();
549 : }
550 1 : }
551 1 : }
552 1 : }
553 :
554 :
555 :
556 2 : void SAL_CALL BaseContainer::addFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener)
557 : throw (css::uno::RuntimeException, std::exception)
558 : {
559 : // no locks necessary
560 : // used helper lives if we live and is threadsafe by itself ...
561 2 : m_lListener.addInterface(cppu::UnoType<css::util::XFlushListener>::get(), xListener);
562 2 : }
563 :
564 :
565 :
566 1 : void SAL_CALL BaseContainer::removeFlushListener(const css::uno::Reference< css::util::XFlushListener >& xListener)
567 : throw (css::uno::RuntimeException, std::exception)
568 : {
569 : // no locks necessary
570 : // used helper lives if we live and is threadsafe by itself ...
571 1 : m_lListener.removeInterface(cppu::UnoType<css::util::XFlushListener>::get(), xListener);
572 1 : }
573 :
574 : } // namespace config
575 : } // namespace filter
576 :
577 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|