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