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