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