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