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