/**
   * Closes given {@link #transportManagers} of this <tt>Conference</tt> and removes corresponding
   * channel bundle.
   */
  void closeTransportManager(TransportManager transportManager) {
    synchronized (transportManagers) {
      for (Iterator<IceUdpTransportManager> i = transportManagers.values().iterator();
          i.hasNext(); ) {
        if (i.next() == transportManager) {
          i.remove();
          // Presumably, we have a single association for
          // transportManager.
          break;
        }
      }

      // Close manager
      try {
        transportManager.close();
      } catch (Throwable t) {
        logger.warn(
            "Failed to close an IceUdpTransportManager of" + " conference " + getID() + "!", t);
        // The whole point of explicitly closing the
        // transportManagers of this Conference is to prevent memory
        // leaks. Hence, it does not make sense to possibly leave
        // TransportManagers open because a TransportManager has
        // failed to close.
        if (t instanceof InterruptedException) Thread.currentThread().interrupt();
        else if (t instanceof ThreadDeath) throw (ThreadDeath) t;
      }
    }
  }
  /**
   * Returns, the <tt>TransportManager</tt> instance for the channel-bundle with ID
   * <tt>channelBundleId</tt>. If no instance exists and <tt>create</tt> is <tt>true</tt>, one will
   * be created.
   *
   * @param channelBundleId the ID of the channel-bundle for which to return the
   *     <tt>TransportManager</tt>.
   * @param create whether to create a new instance, if one doesn't exist.
   * @return the <tt>TransportManager</tt> instance for the channel-bundle with ID
   *     <tt>channelBundleId</tt>.
   */
  IceUdpTransportManager getTransportManager(String channelBundleId, boolean create) {
    IceUdpTransportManager transportManager;

    synchronized (transportManagers) {
      transportManager = transportManagers.get(channelBundleId);
      if (transportManager == null && create && !isExpired()) {
        try {
          // FIXME: the initiator is hard-coded
          // We assume rtcp-mux when bundle is used, so we make only
          // one component.
          transportManager = new IceUdpTransportManager(this, true, 1);
        } catch (IOException ioe) {
          throw new UndeclaredThrowableException(ioe);
        }
        transportManagers.put(channelBundleId, transportManager);
      }
    }

    return transportManager;
  }
  /**
   * Adds the channel-bundles of this <tt>Conference</tt> as
   * <tt>ColibriConferenceIQ.ChannelBundle</tt> instances in <tt>iq</tt>.
   *
   * @param iq the <tt>ColibriConferenceIQ</tt> in which to describe.
   */
  void describeChannelBundles(ColibriConferenceIQ iq) {
    synchronized (transportManagers) {
      for (Map.Entry<String, IceUdpTransportManager> entry : transportManagers.entrySet()) {
        ColibriConferenceIQ.ChannelBundle responseBundleIQ =
            new ColibriConferenceIQ.ChannelBundle(entry.getKey());

        entry.getValue().describe(responseBundleIQ);
        iq.addChannelBundle(responseBundleIQ);
      }
    }
  }
  /** Closes the {@link #transportManagers} of this <tt>Conference</tt>. */
  private void closeTransportManagers() {
    synchronized (transportManagers) {
      for (Iterator<IceUdpTransportManager> i = transportManagers.values().iterator();
          i.hasNext(); ) {
        IceUdpTransportManager transportManager = i.next();

        i.remove();
        closeTransportManager(transportManager);
      }
    }
  }