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