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 #ifndef _CPPUHELPER_INTERFACECONTAINER_H_
24 #define _CPPUHELPER_INTERFACECONTAINER_H_
25 
26 #include <vector>
27 #include <osl/mutex.hxx>
28 #include <rtl/alloc.h>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <com/sun/star/uno/XInterface.hpp>
31 #ifndef _COM_SUN_STAR_LANG_EVENTOBJECT_HXX_
32 #include <com/sun/star/lang/EventObject.hpp>
33 #endif
34 
35 #ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HXX_
36 #include "com/sun/star/lang/DisposedException.hpp"
37 #endif
38 
39 /** */ //for docpp
40 namespace cppu
41 {
42 
43 namespace detail {
44 
45     union element_alias
46     {
47         ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > *pAsSequence;
48         ::com::sun::star::uno::XInterface * pAsInterface;
element_alias()49         element_alias() : pAsInterface(0) {}
50     };
51 
52 }
53 
54 //===================================================================
55 class OInterfaceContainerHelper;
56 /**
57   This is the iterator of a InterfaceContainerHelper. Typically
58   one constructs an instance on the stack for one firing session.
59   It is not allowed to assign or copy an instance of this class.
60 
61   @see OInterfaceContainerHelper
62  */
63 class OInterfaceIteratorHelper
64 {
65 public:
66 	/**
67 	   Create an iterator over the elements of the container. The iterator
68 	   copies the elements of the conatainer. A change to the container
69        during the lifetime of an iterator is allowed and does not
70 	   affect the iterator-instance. The iterator and the container take cares
71        themself for concurrent access, no additional guarding is necessary.
72 
73 	   Remark: The copy is on demand. The iterator copy the elements only if the container
74 	   change the contents. It is not allowed to destroy the container as long
75        as an iterator exist.
76 
77 	   @param rCont	the container of the elements.
78 	 */
79 	OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont ) SAL_THROW( () );
80 
81 	/**
82 	  Releases the connection to the container.
83 	 */
84 	~OInterfaceIteratorHelper() SAL_THROW( () );
85 
86 	/** Return sal_True, if there are more elements in the iterator. */
hasMoreElements() const87 	sal_Bool SAL_CALL hasMoreElements() const SAL_THROW( () )
88 		{ return nRemain != 0; }
89 	/** Return the next element of the iterator. Calling this method if
90 	    hasMoreElements() has returned sal_False, is an error. Cast the
91         returned pointer to the
92 	 */
93 	::com::sun::star::uno::XInterface *	SAL_CALL next() SAL_THROW( () );
94 
95 	/** Removes the current element (the last one returned by next())
96 	    from the underlying container. Calling this method before
97 		next() has been called or calling it twice with no next()
98 		inbetween is an error.
99 	*/
100 	void SAL_CALL remove() SAL_THROW( () );
101 
102 private:
103 	OInterfaceContainerHelper &	rCont;
104 	sal_Bool					bIsList;
105 
106     detail::element_alias aData;
107 
108 	sal_Int32					nRemain;
109 
110 	OInterfaceIteratorHelper( const OInterfaceIteratorHelper & ) SAL_THROW( () );
111 	OInterfaceIteratorHelper &	operator = ( const OInterfaceIteratorHelper & ) SAL_THROW( () );
112 };
113 
114 //===================================================================
115 /**
116   A container of interfaces. To access the elements use an iterator.
117   This implementation is thread save.
118 
119   @see OInterfaceIteratorHelper
120  */
121 class OInterfaceContainerHelper
122 {
123 public:
124 	// these are here to force memory de/allocation to sal lib.
operator new(size_t nSize)125 	inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
126 		{ return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)127 	inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
128 		{ ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)129 	inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
130 		{ return pMem; }
operator delete(void *,void *)131 	inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () )
132 		{}
133 
134 	/**
135 	   Create an interface container.
136 
137 	   @param rMutex	the mutex to protect multi thread access.
138        The lifetime must be longer than the lifetime
139 	   of this object.
140 	 */
141 	OInterfaceContainerHelper( ::osl::Mutex & rMutex ) SAL_THROW( () );
142 	/**
143 	  Release all interfaces. All iterators must be destroyed before
144 	  the container is destructed.
145 	 */
146 	~OInterfaceContainerHelper() SAL_THROW( () );
147 	/**
148 	  Return the number of Elements in the container. Only useful if you have acquired
149 	  the mutex.
150 	 */
151 	sal_Int32 SAL_CALL getLength() const SAL_THROW( () );
152 
153 	/**
154 	  Return all interfaces added to this container.
155 	 **/
156 	::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > > SAL_CALL getElements() const SAL_THROW( () );
157 
158 	/** Inserts an element into the container.  The position is not specified, thus it is not
159         specified in which order events are fired.
160 
161         @attention
162         If you add the same interface more than once, then it will be added to the elements list
163         more than once and thus if you want to remove that interface from the list, you have to call
164         removeInterface() the same number of times.
165         In the latter case, you will also get events fired more than once (if the interface is a
166         listener interface).
167 
168         @param rxIFace
169                interface to be added; it is allowed to insert null or
170                the same interface more than once
171         @return
172                 the new count of elements in the container
173     */
174 	sal_Int32 SAL_CALL addInterface( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) SAL_THROW( () );
175 	/** Removes an element from the container.  It uses interface equality to remove the interface.
176 
177         @param rxIFace
178                interface to be removed
179         @return
180                 the new count of elements in the container
181     */
182 	sal_Int32 SAL_CALL removeInterface( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace ) SAL_THROW( () );
183 	/**
184 	  Call disposing on all object in the container that
185 	  support XEventListener. Than clear the container.
186 	 */
187 	void SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () );
188 	/**
189 	  Clears the container without calling disposing().
190 	 */
191 	void SAL_CALL clear() SAL_THROW( () );
192 
193     /** Executes a functor for each contained listener of specified type, e.g.
194         <code>forEach<awt::XPaintListener>(...</code>.
195 
196         If a com::sun::star::lang::DisposedException occurs which relates to
197         the called listener, then that listener is removed from the container.
198 
199         @tpl ListenerT listener type
200         @tpl FuncT unary functor type, let your compiler deduce this for you
201         @param func unary functor object expecting an argument of type
202                     ::com::sun::star::uno::Reference<ListenerT>
203     */
204     template <typename ListenerT, typename FuncT>
205     inline void forEach( FuncT const& func );
206 
207     /** Calls a UNO listener method for each contained listener.
208 
209         The listener method must take a single argument of type EventT,
210         and return <code>void</code>.
211 
212         If a com::sun::star::lang::DisposedException occurs which relates to
213         the called listener, then that listener is removed from the container.
214 
215         @tpl ListenerT UNO event listener type, let your compiler deduce this for you
216         @tpl EventT event type, let your compiler deduce this for you
217         @param NotificationMethod
218             Pointer to a method of a ListenerT interface.
219         @param Event
220             Event to notify to all contained listeners
221 
222         @example
223 <pre>
224     awt::PaintEvent aEvent( static_cast< ::cppu::OWeakObject* >( this ), ... );
225     listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
226 </pre>
227     */
228     template< typename ListenerT, typename EventT >
229     inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event );
230 
231 private:
232 friend class OInterfaceIteratorHelper;
233 	/**
234 	  bIsList == TRUE -> aData.pAsSequence of type Sequence< XInterfaceSequence >,
235 	  otherwise aData.pAsInterface == of type (XEventListener *)
236 	 */
237     detail::element_alias   aData;
238 	::osl::Mutex &			rMutex;
239 	/** TRUE -> used by an iterator. */
240 	sal_Bool				bInUse;
241 	/** TRUE -> aData.pAsSequence is of type Sequence< XInterfaceSequence >. */
242 	sal_Bool				bIsList;
243 
244 	OInterfaceContainerHelper( const OInterfaceContainerHelper & ) SAL_THROW( () );
245 	OInterfaceContainerHelper & operator = ( const OInterfaceContainerHelper & ) SAL_THROW( () );
246 
247 	/*
248 	  Dulicate content of the conaitner and release the old one without destroying.
249 	  The mutex must be locked and the memberbInUse must be true.
250 	 */
251 	void copyAndResetInUse() SAL_THROW( () );
252 
253 private:
254     template< typename ListenerT, typename EventT >
255     class NotifySingleListener
256     {
257     private:
258         typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
259         NotificationMethod  m_pMethod;
260         const EventT&       m_rEvent;
261     public:
NotifySingleListener(NotificationMethod method,const EventT & event)262         NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
263 
operator ()(const::com::sun::star::uno::Reference<ListenerT> & listener) const264         void operator()( const ::com::sun::star::uno::Reference<ListenerT>& listener ) const
265         {
266             (listener.get()->*m_pMethod)( m_rEvent );
267         }
268     };
269 };
270 
271 template <typename ListenerT, typename FuncT>
forEach(FuncT const & func)272 inline void OInterfaceContainerHelper::forEach( FuncT const& func )
273 {
274     OInterfaceIteratorHelper iter( *this );
275     while (iter.hasMoreElements()) {
276         ::com::sun::star::uno::Reference<ListenerT> const xListener(
277             iter.next(), ::com::sun::star::uno::UNO_QUERY );
278         if (xListener.is()) {
279 #if defined(EXCEPTIONS_OFF)
280             func( xListener );
281 #else
282             try {
283                 func( xListener );
284             }
285             catch (::com::sun::star::lang::DisposedException const& exc) {
286                 if (exc.Context == xListener)
287                     iter.remove();
288             }
289 #endif
290         }
291     }
292 }
293 
294 template< typename ListenerT, typename EventT >
notifyEach(void (SAL_CALL ListenerT::* NotificationMethod)(const EventT &),const EventT & Event)295 inline void OInterfaceContainerHelper::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event )
296 {
297     forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) );
298 }
299 
300 //===================================================================
301 /**
302   A helper class to store interface references of different types.
303 
304   @see OInterfaceIteratorHelper
305   @see OInterfaceContainerHelper
306  */
307 template< class key , class hashImpl , class equalImpl >
308 class OMultiTypeInterfaceContainerHelperVar
309 {
310 public:
311 	// these are here to force memory de/allocation to sal lib.
operator new(size_t nSize)312 	inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
313 		{ return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)314 	inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
315 		{ ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)316 	inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
317 		{ return pMem; }
operator delete(void *,void *)318 	inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () )
319 		{}
320 
321 	/**
322 	  Create a container of interface containers.
323 
324 	  @param rMutex	the mutex to protect multi thread access.
325 	 					The lifetime must be longer than the lifetime
326 	 					of this object.
327 	 */
328 	inline OMultiTypeInterfaceContainerHelperVar( ::osl::Mutex & ) SAL_THROW( () );
329 	/**
330 	  Deletes all containers.
331 	 */
332 	inline ~OMultiTypeInterfaceContainerHelperVar() SAL_THROW( () );
333 
334 	/**
335 	  Return all id's under which at least one interface is added.
336 	 */
337 	inline ::com::sun::star::uno::Sequence< key > SAL_CALL getContainedTypes() const SAL_THROW( () );
338 
339 	/**
340 	  Return the container created under this key.
341       The InterfaceContainerHelper exists until the whole MultiTypeContainer is destroyed.
342 	  @return the container created under this key. If the container
343 	 			was not created, null was returned.
344 	 */
345 	inline OInterfaceContainerHelper * SAL_CALL getContainer( const key & ) const SAL_THROW( () );
346 
347 	/** Inserts an element into the container with the specified key.
348         The position is not specified, thus it is not specified in which order events are fired.
349 
350         @attention
351         If you add the same interface more than once, then it will be added to the elements list
352         more than once and thus if you want to remove that interface from the list, you have to call
353         removeInterface() the same number of times.
354         In the latter case, you will also get events fired more than once (if the interface is a
355         listener interface).
356 
357         @param rKey
358                the id of the container
359         @param r
360                interface to be added; it is allowed, to insert null or
361                the same interface more than once
362         @return
363                 the new count of elements in the container
364     */
365 	inline sal_Int32 SAL_CALL addInterface(
366 		const key & rKey,
367 		const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & r )
368 		SAL_THROW( () );
369 
370 	/** Removes an element from the container with the specified key.
371         It uses interface equality to remove the interface.
372 
373         @param rKey
374                the id of the container
375         @param rxIFace
376                interface to be removed
377         @return
378                 the new count of elements in the container
379     */
380 	inline sal_Int32 SAL_CALL removeInterface(
381 		const key & rKey,
382 		const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace )
383 		SAL_THROW( () );
384 
385 	/**
386 	  Call disposing on all references in the container, that
387 	  support XEventListener. Then clears the container.
388       @param rEvt the event object which is passed during disposing() call
389 	 */
390 	inline void	SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () );
391 	/**
392 	  Remove all elements of all containers. Does not delete the container.
393 	 */
394 	inline void SAL_CALL clear() SAL_THROW( () );
395 
396 	typedef key keyType;
397 private:
398     typedef ::std::vector< std::pair < key , void* > > InterfaceMap;
399     InterfaceMap *m_pMap;
400 	::osl::Mutex &	rMutex;
401 
find(const key & rKey) const402     inline typename InterfaceMap::iterator find(const key &rKey) const
403     {
404         typename InterfaceMap::iterator iter = m_pMap->begin();
405         typename InterfaceMap::iterator end = m_pMap->end();
406 
407     	while( iter != end )
408         {
409             equalImpl equal;
410             if( equal( iter->first, rKey ) )
411                 break;
412             iter++;
413         }
414         return iter;
415     }
416 
417 	inline OMultiTypeInterfaceContainerHelperVar( const OMultiTypeInterfaceContainerHelperVar & ) SAL_THROW( () );
418 	inline OMultiTypeInterfaceContainerHelperVar & operator = ( const OMultiTypeInterfaceContainerHelperVar & ) SAL_THROW( () );
419 };
420 
421 
422 
423 
424 /**
425   This struct contains the standard variables of a broadcaster. Helper
426   classes only know a reference to this struct instead of references
427   to the four members. The access to the members must be guarded with
428   rMutex.
429 
430   The additional template parameter keyType has been added, because gcc
431   can't compile addListener( const container::keyType &key ).
432  */
433 template < class container , class keyType >
434 struct OBroadcastHelperVar
435 {
436 	/** The shared mutex. */
437 	::osl::Mutex &						rMutex;
438 	/** ListenerContainer class is thread save. */
439 	container	aLC;
440 	/** Dispose call ready. */
441 	sal_Bool							bDisposed;
442 	/** In dispose call. */
443 	sal_Bool							bInDispose;
444 
445 	/**
446 	  Initialize the structur. bDispose and bInDispose are set to false.
447 	  @param rMutex the mutex reference.
448 	 */
449 	OBroadcastHelperVar( ::osl::Mutex & rMutex_ ) SAL_THROW( () )
450 		: rMutex( rMutex_ )
451 		, aLC( rMutex_ )
452 		, bDisposed( sal_False )
453 		, bInDispose( sal_False )
454 	{}
455 
456 	/**
457 	  adds a listener threadsafe.
458 	 **/
addListenercppu::OBroadcastHelperVar459 	inline void addListener(
460 		const keyType &key,
461 		const ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > &r )
462 		SAL_THROW( () )
463 	{
464 		::osl::MutexGuard guard( rMutex );
465 		OSL_ENSURE( !bInDispose, "do not add listeners in the dispose call" );
466 		OSL_ENSURE( !bDisposed, "object is disposed" );
467 		if( ! bInDispose && ! bDisposed  )
468 			aLC.addInterface( key , r );
469 	}
470 
471 	/**
472 	  removes a listener threadsafe
473 	 **/
removeListenercppu::OBroadcastHelperVar474 	inline void removeListener(
475 		const keyType &key,
476 		const ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > & r )
477 		SAL_THROW( () )
478 	{
479 		::osl::MutexGuard guard( rMutex );
480 		OSL_ENSURE( !bDisposed, "object is disposed" );
481 		if( ! bInDispose && ! bDisposed  )
482 			aLC.removeInterface( key , r );
483 	}
484 
485 	/**
486 	  Return the container created under this key.
487 	  @return the container created under this key. If the container
488 	 		   was not created, null was returned. This can be used to optimize
489 	          performance ( construction of an event object can be avoided ).
490 	 ***/
getContainercppu::OBroadcastHelperVar491 	inline OInterfaceContainerHelper * SAL_CALL getContainer( const keyType &key ) const SAL_THROW( () )
492 		{ return aLC.getContainer( key ); }
493 };
494 
495 /*------------------------------------------
496 *
497 * In general, the above templates are used with a Type as key.
498 * Therefore a default declaration is given ( OMultiTypeInterfaceContainerHelper and OBroadcastHelper )
499 *
500 *------------------------------------------*/
501 
502 // helper function call class
503 struct hashType_Impl
504 {
operator ()cppu::hashType_Impl505 	size_t operator()(const ::com::sun::star::uno::Type & s) const SAL_THROW( () )
506 		{ return s.getTypeName().hashCode(); }
507 };
508 
509 
510 /** Specialized class for key type com::sun::star::uno::Type,
511     without explicit usage of STL symbols.
512 */
513 class OMultiTypeInterfaceContainerHelper
514 {
515 public:
516 	// these are here to force memory de/allocation to sal lib.
operator new(size_t nSize)517 	inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
518 		{ return ::rtl_allocateMemory( nSize ); }
operator delete(void * pMem)519 	inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
520 		{ ::rtl_freeMemory( pMem ); }
operator new(size_t,void * pMem)521 	inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () )
522 		{ return pMem; }
operator delete(void *,void *)523 	inline static void SAL_CALL operator delete( void *, void * ) SAL_THROW( () )
524 		{}
525 
526 	/**
527 	  Create a container of interface containers.
528 
529 	  @param rMutex	the mutex to protect multi thread access.
530 	 					The lifetime must be longer than the lifetime
531 	 					of this object.
532 	 */
533 	OMultiTypeInterfaceContainerHelper( ::osl::Mutex & ) SAL_THROW( () );
534 	/**
535 	  Delete all containers.
536 	 */
537 	~OMultiTypeInterfaceContainerHelper() SAL_THROW( () );
538 
539 	/**
540 	  Return all id's under which at least one interface is added.
541 	 */
542 	::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getContainedTypes() const SAL_THROW( () );
543 
544 	/**
545 	  Return the container created under this key.
546 	  @return the container created under this key. If the container
547 	 			was not created, null was returned.
548 	 */
549 	OInterfaceContainerHelper * SAL_CALL getContainer( const ::com::sun::star::uno::Type & rKey ) const SAL_THROW( () );
550 
551 	/** Inserts an element into the container with the specified key.
552         The position is not specified, thus it is not specified in which order events are fired.
553 
554         @attention
555         If you add the same interface more than once, then it will be added to the elements list
556         more than once and thus if you want to remove that interface from the list, you have to call
557         removeInterface() the same number of times.
558         In the latter case, you will also get events fired more than once (if the interface is a
559         listener interface).
560 
561         @param rKey
562                the id of the container
563         @param r
564                interface to be added; it is allowed, to insert null or
565                the same interface more than once
566         @return
567                 the new count of elements in the container
568     */
569 	sal_Int32 SAL_CALL addInterface(
570 		const ::com::sun::star::uno::Type & rKey,
571 		const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & r )
572 		SAL_THROW( () );
573 
574 	/** Removes an element from the container with the specified key.
575         It uses interface equality to remove the interface.
576 
577         @param rKey
578                the id of the container
579         @param rxIFace
580                interface to be removed
581         @return
582                 the new count of elements in the container
583     */
584 	sal_Int32 SAL_CALL removeInterface(
585 		const ::com::sun::star::uno::Type & rKey,
586 		const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rxIFace )
587 		SAL_THROW( () );
588 
589 	/**
590 	  Call disposing on all object in the container that
591 	  support XEventListener. Than clear the container.
592 	 */
593 	void	SAL_CALL disposeAndClear( const ::com::sun::star::lang::EventObject & rEvt ) SAL_THROW( () );
594 	/**
595 	  Remove all elements of all containers. Does not delete the container.
596 	 */
597 	void SAL_CALL clear() SAL_THROW( () );
598 
599 	typedef ::com::sun::star::uno::Type keyType;
600 private:
601 	void *m_pMap;
602 	::osl::Mutex &	rMutex;
603 
604 	inline OMultiTypeInterfaceContainerHelper( const OMultiTypeInterfaceContainerHelper & ) SAL_THROW( () );
605 	inline OMultiTypeInterfaceContainerHelper & operator = ( const OMultiTypeInterfaceContainerHelper & ) SAL_THROW( () );
606 };
607 
608 typedef OBroadcastHelperVar< OMultiTypeInterfaceContainerHelper , OMultiTypeInterfaceContainerHelper::keyType > OBroadcastHelper;
609 
610 }
611 
612 #endif
613 
614