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