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; 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. */ 87 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. 125 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 126 { return ::rtl_allocateMemory( nSize ); } 127 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 128 { ::rtl_freeMemory( pMem ); } 129 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 130 { return pMem; } 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: 262 NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { } 263 264 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> 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 > 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. 312 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 313 { return ::rtl_allocateMemory( nSize ); } 314 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 315 { ::rtl_freeMemory( pMem ); } 316 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 317 { return pMem; } 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 402 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 **/ 459 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 **/ 474 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 ***/ 491 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 { 505 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. 517 inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () ) 518 { return ::rtl_allocateMemory( nSize ); } 519 inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () ) 520 { ::rtl_freeMemory( pMem ); } 521 inline static void * SAL_CALL operator new( size_t, void * pMem ) SAL_THROW( () ) 522 { return pMem; } 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