/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_OUT_OF_BAND_CHANNEL_HPP
#define NMM_OUT_OF_BAND_CHANNEL_HPP NMM_OUT_OF_BAND_CHANNEL_HPP

#include "nmm/nmm_prefix.hpp"

#include "CommunicationChannel.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class Interface;
  class ProxyObject;
  class NMMObject;
  class ITransportStrategy;
  class OutOfBandCompositeStrategy;
  class IOutOfBandCompositeStrategy;
  class TSAddress;
  
  /** Out-of-band Communication Channel.
   * This communication channel represents the connection between a %ProxyObject and an %NMMObject,
   * which is called out-of-band connection. Every out-of-band connection combines three communication
   * roles: Event request, event reply and listener notification. The %ProxyObject sends events to
   * the %NMMObject (event request) and waits for the %NMMObject to send them back (event reply) to
   * realize blocking function calls. The %NMMObject may also send events to the %ProxyObject if the
   * %ProxyObject has registered an event listener (listener notification).
   * @see ProxyObject
   * @see NMMObject
   * @todo Set the ValueStream for the TransportStrategy
   * @todo Extend CompositeStrategy to support out-of-band
   */
  class DLLEXPORT OutOfBandChannel
    : public CommunicationChannel
  {
  public:
    /** Communication roles for sub-bindings.
     */
    enum CommunicationRole {
      REQUEST               = 1,                                     ///< Event request
      REPLY                 = 2,                                     ///< Event reply
      LISTENER_REQUEST      = 4,                                     ///< Event listener notification request
      LISTENER_REPLY        = 8,                                     ///< Event listener notification reply
      
      REQUEST_REPLY         = REQUEST | REPLY,                       ///< Event request and reply
      LISTENER_NOTIFICATION = LISTENER_REQUEST | LISTENER_REPLY,     ///< Event listener notification
      OUT_OF_BAND           = REQUEST_REPLY | LISTENER_NOTIFICATION  ///< All roles
    };
    
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructs an %OutOfBandChannel with an %Interface.
     *
     * This constructor creates an %OutOfBandChannel for the given @c parent object and @c interface.
     * The available transport strategies and addresses are given by the interface.
     *
     * @param parent Parent peoxy object
     * @param interface Interface to a remote object
     */
    OutOfBandChannel(ProxyObject& parent, const Interface& _interface);
    
    /** Constructs an %OutOfBandChannel with an address.
     *
     * This constructor creates an %OutOfBandChannel for the given @c parent object and @c address.
     * Only the given address and its associated transport strategy can be used.
     *
     * @param parent Parent proxy object
     * @param address Address to connect to
     */
    OutOfBandChannel(ProxyObject& parent, const TSAddress& address);
    
    /** Constructs an %OutOfBandChannel for an object.
     *
     * This constructor is used by %NMMObject to create the server side of an out-of-band connection.
     *
     * @param parent Parent NMM object
     */
    OutOfBandChannel(NMMObject& parent);
    
    /** Copy Constructor.
     *
     * @param obc OutOfBandChannel to be copied
     */
    OutOfBandChannel(const OutOfBandChannel& obc);
    
    /** Virtual Copy Constructor.
     */
    virtual OutOfBandChannel* copy() const;
    
    /** Virtual destructor.
     */
    virtual ~OutOfBandChannel();
    //@}
    
    /** @name Configuration
     */
    //@{
    /** Returns a list of all TransportStrategies available for the connection.
     *
     * @return list of all TransportStrategies available for the connection
     */
    virtual list<string> getStrategyList() const;
    
    /** This method returns a list of all TransportStrategies with the given interfaces.
     *
     * Possible flags for interfaces are defined in class TSFactory.
     *
     * @param request_interfaces Requested interfaces at the request side.
     * @param reply_interfaces Requested interfaces at the reply side.
     * @return A list of suitable strategies
     */
    virtual list<string> getStrategyList(unsigned int request_interfaces, unsigned int reply_interfaces) const;
    
    /** This method returns a list of all TransportStrategies which can be used for the given combination of roles.
     *
     * @param roles Requested roles
     * @return A list of suitable strategies
     */
    virtual list<string> getStrategyList(unsigned int roles) const;
    
    /** Adds a %TransportStrategy to the configuration.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     * If any roles are unset when establishBinding is called, then this strategy may be reused for unset roles.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param request_interfaces Interfaces at the request side
     * @param reply_interfaces Interfaces at the reply side
     * @exception BindingException if the configuration is invalid
     */
    virtual void addTransportStrategy(const string& strategy_type, unsigned int request_interfaces, unsigned int reply_interfaces)
      throw(const BindingException&);

    /** Adds a %TransportStrategy to the configuration and disallow reuse.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param request_interfaces Interfaces at the request side
     * @param reply_interfaces Interfaces at the reply side
     * @exception BindingException if the configuration is invalid
     */
    virtual void addExplicitTransportStrategy(const string& strategy_type, unsigned int request_interfaces, unsigned int reply_interfaces)
      throw(const BindingException&);
    
    /** Adds a %TransportStrategy to the configuration.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     * If any roles are unset when establishBinding is called, then this strategy may be reused for unset roles.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param roles Combination of rules to use the strategy for
     * @exception BindingException if the configuration is invalid
     */
    virtual void addTransportStrategy(const string& strategy_type, unsigned int roles)
      throw(const BindingException&);
    
    /** Adds a %TransportStrategy to the configuration and disallow reuse.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param roles Combination of rules to use the strategy for
     * @exception BindingException if the configuration is invalid
     */
    virtual void addExplicitTransportStrategy(const string& strategy_type, unsigned int roles)
      throw(const BindingException&);
    
    /** Establishes the binding.
     *
     * This method must be called when the configuration of the channel is finished. After calling this method, no more strategies
     * may be added.
     * If not all roles have been assigned a %TransportStrategy yet, then this method will complete the configuration automatically.
     * If any strategies have been added with addExplicitTransportStrategy, then this method will first try to use them for unset roles.
     * Otherwise default strategies will be added.
     * @exception BindingException if the binding could not be established
     */
    virtual void establishBinding() throw(const BindingException&);
    
    /** Unsets all transport strategies.
     * This method destroys all transport strategies and resets the configuration.
     */
    virtual void unsetTransportStrategy();
    
    /** Sets a value stream.
     *
     * This method sets the type of %ValueStream for data serialization.
     *
     * @param roles Combination of flags from %CommunicationRole specifying the communication roles to set the value stream for.
     * @param i_value_stream_type Type name of input value stream.
     * @param o_value_stream_type Type name of output value stream.
     */
    virtual void setValueStream(unsigned int roles, const string& i_value_stream_type, const string& o_value_stream_type);

    /** Sets value stream.
     *
     * This method sets a %ValueStream stack for data serialization.
     *
     * @param roles Combination of flags from %CommunicationRole specifying the communication roles to set the value stream for.
     * @param i_value_stream_type Type name of input value stream.
     * @param o_value_stream_type Type name of output value stream.
     */
    virtual void setValueStreamStack(unsigned int roles, const IValueStream* i_value_stream_type, const OValueStream* o_value_stream_type);
    //@}
    
    /** @name Access Communication Channel information
     */
    //@{
    /** Returns the local top-level transport strategy.
     *
     * @return top-level transport strategy.
     */
    inline OutOfBandCompositeStrategy* getTransportStrategy() const {
      return __strategy;
    }
    
    /** Returns the top-level transport strategy on the request side.
     *
     * @return top-level transport strategy on the request side.
     */
    IOutOfBandCompositeStrategy* getRequestStrategy() const;
    
    /** Returns the top-level transport strategy on the reply side.
     *
     * @return top-level transport strategy on the reply side.
     */
    IOutOfBandCompositeStrategy* getReplyStrategy() const;
    
    /** Returns the leaf transport strategy with the given communication role on the request side.
     *
     * @param role specifies the CommunicationRole
     * @return leaf transport strategy with the given communication role on the request side.
     */
    ITransportStrategy* getRequestStrategy(CommunicationRole role) const;
    
    /** Returns the leaf transport strategy with the given communication role on the reply side.
     *
     * @param role specifies the CommunicationRole
     * @return leaf transport strategy with the given communication role on the reply side.
     */
    ITransportStrategy* getReplyStrategy(CommunicationRole role) const;
    
    /** This method returns a reference to the %NMMObject that uses this communicatio channel.
     *
     * @return reference to the ParentObject
     */
    inline       NMMObject&         getParent()                           { return __parent; }
    
    /** This method returns a reference to the %NMMObject that uses this communicatio channel.
     *
     * @return reference to the ParentObject
     */
    inline const NMMObject&         getParent()                     const { return __parent; }
    
    /** This method sets the transport strategy.
     *
     * @param strategy OutOfBancCompositeStrategy to set.
     */
    void setTransportStrategy(OutOfBandCompositeStrategy* strategy);
    //@}
    
    /** @name Access the TransportStrategy Interfaces
     */
    //@{
    /** Returns an interface to the top-level %TransportStrategy of the %NMMObject.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @return interface of type T
     */
    template<class T>
    T* getReplyInterface();
    
    /** Returns an interface to the top-level %TransportStrategy of the %NMMObject.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @return interface of type T
     */
    template<class T>
    const T* getReplyInterface() const;
    
    /** Returns an interface to the top-level %TransportStrategy %ProxyObject.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    T* getRequestInterface();
    
    /** Returns an interface to the top-level %TransportStrategy %ProxyObject.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @return interface of type T
     */
    template<class T>
    const T* getRequestInterface()   const;

    /** Returns an interface to the leaf %TransportStrategy of the %NMMObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @return interface of type T
     */
    template<class T>
    T* getReplyInterface(CommunicationRole role);
    
    /** Returns an interface to the leaf %TransportStrategy of the %NMMObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @param role CommunicationRole to be fullfilled by interace
     * @return interface of type T
     */
    template<class T>
    const T* getReplyInterface(CommunicationRole role) const;
    
    /** Returns an interface to the leaf %TransportStrategy %ProxyObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @param role CommunicationRole to be fullfilled by interace
     * @return interface of type T
     */
    template<class T>
    T* getRequestInterface(CommunicationRole role);
    
    /** Returns an interface to the leaf %TransportStrategy %ProxyObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     *
     * @param role CommunicationRole to be fullfilled by interace
     * @return interface of type T
     */
    template<class T>
    const T* getRequestInterface(CommunicationRole role)   const;
    
    /** This method returns a list of all Interfaces to the top-level TransportStrategy of the %NMMObject.
     *
     * @return list of all Interfaces to the top-level TransportStrategy of the %NMMObject
     */
    virtual list<Interface*>& getReplyInterfaceList();
    
    /** This method returns a list of all Interfaces to the top-level TransportStrategy %ProxyObject.
     *
     * @return list of all Interfaces to the top-level TransportStrategy %ProxyObject
     */
    virtual list<Interface*>& getRequestInterfaceList();
    
    /** This method returns a list of all Interfaces to the leaf TransportStrategy of the %NMMObject with the given communication role.
     *
     * @param role Communication role
     * @return list of all Interfaces to the leaf TransportStrategy of the %NMMObject with the given communication role
     */
    virtual list<Interface*>& getReplyInterfaceList(CommunicationRole role);
    
    /** This method returns a list of all Interfaces to the leaf TransportStrategy %ProxyObject with the given communication role.
     *
     * @param role Communication role
     * @return list of all Interfaces to the leaf TransportStrategy %ProxyObject with the given communication role
     */
    virtual list<Interface*>& getRequestInterfaceList(CommunicationRole role);
    //@}
    
  private:
    /** This method updates the interfaces of the set transport strategy.
     */
    void updateStrategyInterfaces();
    
    /** This method adds a connection address.
     * 
     * @param tsaddress connection address
     */
    void addAddress(const TSAddress& tsaddress);
    
    /** This method returns the TSAddress for a specific TransportStrategy strategy.
     *
     * @param strategy TransportStrategy to return TSAddress for
     * @return pointer to TSAddress of given TransportStrategy
     */
    const TSAddress* getAddress(const string& strategy)      const;
    
    /** Updates strategy list.
     *
     * This method updates the list of available transport strategies based on the given @c interface.
     * All addresses and %TransportStrategy descriptions from the interface are added to the strategy and
     * address lists of this channel.
     *
     * @param interface An interface for which this channel should be configured
     */
    void updateStrategyList(const Interface& iface);
    
    /** Tries to reuse an already added strategy with the given interfaces.
     *
     * This method is used by automatic binding configuration to find an already added %TransportStrategy which
     * supports at least the given interfaces. If a strategy is found, it is added to the configuration.
     *
     * @param request_interfaces bitmask defining which interfaces must exist on requesting side
     * @param reply_interfaces bitmask defining which interfaces must exist on replying side
     * @return @c true if a suitable strategy was found, otherwise @c false
     */
    bool tryReuseStrategy(unsigned int request_interfaces, unsigned int reply_interfaces);
    
    /** Tries to find a suitable strategy with the given interfaces.
     *
     * This method is used by automatic binding configuration to find a new %TransportStrategy which
     * supports at least the given interfaces. If a strategy is found, it is added to the configuration.
     *
     * @param request_interfaces bitmask defining which interfaces must exist on requesting side
     * @param reply_interfaces bitmask defining which interfaces must exist on replying side
     * @return @c true if a suitable strategy was found, otherwise @c false
     */
    bool findSuitableStrategy(unsigned int request_interfaces, unsigned int reply_interfaces);
    
    /** Actual implementation of addTransportStrategy.
     *
     * @param strategy_type type of TransportStrategy
     * @param request_interfaces bitmask defining interfaces on requesting side
     * @param reply_interfaces bitmask defining interfaces on replying side
     * @param is_explicit true if TransportStrategy is explicit, false otherwise
     * @exception BindingException if the configuration is invalid
     */
    void addTransportStrategyInternal(const string& strategy_type, unsigned int request_interfaces, unsigned int reply_interfaces,
                                      bool is_explicit)
      throw(const BindingException&);
    
    /** Actual implementation of addTransportStrategy.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param roles Combination of roles to use the strategy for
     * @exception BindingException if the configuration is invalid
     */    
    void addTransportStrategyInternal(const string& strategy_type, unsigned int roles, bool is_explicit)
      throw(const BindingException&);
    
    /** Sets value stream for a single communication role.
     *
     * @param role Combination of roles to use the strategy for
     * @param i_value_stream_type input value stream type
     * @param o_value_stream_type output value stream type
     */
    void setValueStreamInternal(CommunicationRole role, const string& i_value_stream_type, const string& o_value_stream_type);
    
    /** Sets value stream for a single communication role.
     *
     * @param role Combination of roles to use the strategy for
     * @param i_value_stream_type interface to input value stream 
     * @param o_value_stream_type interface to output value stream 
     */
    void setValueStreamStackInternal(CommunicationRole role, const IValueStream* i_value_stream_type, const OValueStream* o_value_stream_type);
    
  private:
    NMMObject&                   __parent;              ///< The Parent object which uses this channel
    
    /* BEGIN> Configuration */
    /** A matching pair of transport strategies that can be used.
     */
    struct StrategyListEntry {
      string strategy_type;                             ///< Type name of TransportStrategy.
      bool is_explicit;                                 ///< Transport strategy is explicit.
      unsigned int capabilities;                        ///< Capabilities of TransportStrategy.
      unsigned int request_interfaces;                  ///< Interfaces on the request side.
      unsigned int reply_interfaces;                    ///< Interfaces on the reply side.
      unsigned int used_request_interfaces;             ///< Used interfaces on the request side.
      unsigned int used_reply_interfaces;               ///< Used interfaces on the reply side.
      TSAddress* default_address;                       ///< Default address.
      
      /** Constructor. 
       */
      StrategyListEntry() throw()
        : strategy_type(),
          is_explicit(false),
          capabilities(0),
          request_interfaces(0),
          reply_interfaces(0),
          used_request_interfaces(0),
          used_reply_interfaces(0),
          default_address(0)
      {}
      
      /** Comparison operator.
       *
       * @param other StrategyListEntry to compare with
       * @return true, if entries are equal, false otherwise
       */
      bool operator==(const StrategyListEntry& other) const {
        return strategy_type == other.strategy_type &&
          capabilities == other.capabilities &&
          request_interfaces == other.request_interfaces &&
          reply_interfaces == other.reply_interfaces;
      }
    };
    
    typedef list<StrategyListEntry>       StrategyList;
    typedef StrategyList::iterator        StrategyIterator;
    typedef StrategyList::const_iterator  StrategyConstIterator; 
   
    StrategyList                __strategy_list;        ///< List of available strategies and their capabilities
    vector<StrategyListEntry>   __strategies;           ///< Selected transport strategies
    /* END< */
    
    /* BEGIN> Transport strategies */
    mutable OutOfBandCompositeStrategy*  __strategy;               ///< Pointer to the local %TransportStrategy
    mutable IOutOfBandCompositeStrategy* __request_strategy;       ///< Interface to the top-level %TransportStrategy on the request side.
    mutable IOutOfBandCompositeStrategy* __reply_strategy;         ///< Interface to the top-level %TransportStrategy on the reply side.
    mutable bool                         __request_strategy_valid; ///< Interface to the top-level %TransportStrategy on the request side is valid.
    mutable bool                         __reply_strategy_valid;   ///< Interface to the top-level %TransportStrategy on the request side is valid.
    mutable ITransportStrategy* __request_child_strategy[4];       ///< Interface to the leaf TransportStrategies on the request side.
    mutable ITransportStrategy* __reply_child_strategy[4];         ///< Interface to the leaf TransportStrategies on the reply side.
    mutable bool                __request_child_strategy_valid[4]; ///< Interface to the leaf TransportStrategies on the request side are valid.
    mutable bool                __reply_child_strategy_valid[4];   ///< Interface to the leaf TransportStrategies on the request side are valid.
    /* END< */
    
  public:
    /** This method returns the TypeInfo for this class.
     *
     * @return TypeInfo
     */
    static TypeInfo getStaticTypeInfo();
  };

  /** Returns a copy of reply interface.
     *
     * This template method returns copy of reply interface of type T or NULL if this interface
     * is not supported by this object. 
     * 
     * @return pointer to Interface of type T
     */
  template <typename T>
  T* OutOfBandChannel::getReplyInterface() {
    T* interface = 0;
    for (list<Interface*>::iterator it = getReplyInterfaceList().begin(); it != getReplyInterfaceList().end(); ++it)
      {
        interface = dynamic_cast<T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns a copy of reply interface.
     *
     * This template method returns copy of reply interface of type T or NULL if this interface
     * is not supported by this object. 
     * 
     * @return pointer to Interface of type T
     */template <typename T>
  const T* OutOfBandChannel::getReplyInterface() const {
    const T* interface = 0;
    for (list<Interface*>::const_iterator it = getReplyInterfaceList().begin(); it != getReplyInterfaceList().end(); ++it)
      {
        interface = dynamic_cast<const T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns a copy of request interface.
     *
     * This template method returns copy of request interface of type T or NULL if this interface
     * is not supported by this object. 
     * 
     * @return pointer to Interface of type T
     */
  template <typename T>
  T* OutOfBandChannel::getRequestInterface() {
    T* interface = 0;
    for (list<Interface*>::iterator it = getRequestInterfaceList().begin(); it != getRequestInterfaceList().end(); ++it)
      {
        interface = dynamic_cast<T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns a copy of request interface.
     *
     * This template method returns copy of request interface of type T or NULL if this interface
     * is not supported by this object. 
     * 
     * @return pointer to interface of type T
     */
  template <typename T>
  const T* OutOfBandChannel::getRequestInterface() const {
    const T* interface = 0;
    for (list<Interface*>::const_iterator it = getRequestInterfaceList().begin(); it != getRequestInterfaceList().end(); ++it)
      {
        interface = dynamic_cast<const T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }

  /** Returns an interface to the leaf %TransportStrategy of the %NMMObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     *
     * @param role CommuncationRole
     * @return pointer to interface of type T 
     */
  template <typename T>
  T* OutOfBandChannel::getReplyInterface(CommunicationRole role) {
    T* interface = 0;
    for (list<Interface*>::iterator it = getReplyInterfaceList(role).begin(); it != getReplyInterfaceList(role).end(); ++it)
      {
        interface = dynamic_cast<T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns an interface to the leaf %TransportStrategy of the %NMMObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     *
     * @param role CommuncationRole
     * @return pointer to interface of type T 
     */
  template <typename T>
  const T* OutOfBandChannel::getReplyInterface(CommunicationRole role) const {
    const T* interface = 0;
    for (list<Interface*>::const_iterator it = getReplyInterfaceList(role).begin(); it != getReplyInterfaceList(role).end(); ++it)
      {
        interface = dynamic_cast<const T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns an interface to the leaf %TransportStrategy %ProxyObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     *
     * @param role CommunicationRole
     * @return pointer to interface of type T 
     */
  template <typename T>
  T* OutOfBandChannel::getRequestInterface(CommunicationRole role) {
    T* interface = 0;
    for (list<Interface*>::iterator it = getRequestInterfaceList(role).begin(); it != getRequestInterfaceList(role).end(); ++it)
      {
        interface = dynamic_cast<T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
  /** Returns an interface to the leaf %TransportStrategy %ProxyObject with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     *
     * @param role CommunicationRole
     * @return pointer to interface of type T 
     */
  template <typename T>
  const T* OutOfBandChannel::getRequestInterface(CommunicationRole role) const {
    const T* interface = 0;
    for (list<Interface*>::const_iterator it = getRequestInterfaceList(role).begin(); it != getRequestInterfaceList(role).end(); ++it)
      {
        interface = dynamic_cast<const T*>(*it);
        if (interface != 0)
          return dynamic_cast<T* >(interface->copy());
      }
    return 0;
  }
  
}

#include "nmm/nmm_suffix.hpp"

#endif
