/**
   * Creates and sends a SUBSCRIBE request to the subscription <tt>Address</tt>/Request URI of a
   * specific <tt>Subscription</tt> in order to request receiving event notifications and adds the
   * specified <tt>Subscription</tt> to the list of subscriptions managed by this instance. The
   * added <tt>Subscription</tt> may later receive notifications to process the <tt>Request</tt>s
   * and/or <tt>Response</tt>s which constitute the signaling session associated with it. If the
   * attempt to create and send the SUBSCRIBE request fails, the specified <tt>Subscription</tt> is
   * not added to the list of subscriptions managed by this instance.
   *
   * @param subscription a <tt>Subscription</tt> which specifies the properties of the SUBSCRIBE
   *     request to be created and sent, to be added to the list of subscriptions managed by this
   *     instance
   * @throws OperationFailedException if we fail constructing or sending the subscription request.
   */
  public void subscribe(Subscription subscription) throws OperationFailedException {
    Dialog dialog = subscription.getDialog();

    if ((dialog != null) && DialogState.TERMINATED.equals(dialog.getState())) dialog = null;

    // create the subscription
    ClientTransaction subscribeTransaction = null;
    try {
      subscribeTransaction =
          (dialog == null)
              ? createSubscription(subscription, subscriptionDuration)
              : createSubscription(subscription, dialog, subscriptionDuration);
    } catch (OperationFailedException ex) {
      ProtocolProviderServiceSipImpl.throwOperationFailedException(
          "Failed to create the subscription", OperationFailedException.INTERNAL_ERROR, ex, logger);
    }

    // we register the contact to find him when the OK will arrive
    CallIdHeader callIdHeader =
        (CallIdHeader) subscribeTransaction.getRequest().getHeader(CallIdHeader.NAME);
    String callId = callIdHeader.getCallId();
    addSubscription(callId, subscription);

    // send the message
    try {
      if (dialog == null) subscribeTransaction.sendRequest();
      else dialog.sendRequest(subscribeTransaction);
    } catch (SipException ex) {
      // this contact will never been accepted or rejected
      removeSubscription(callId, subscription);

      ProtocolProviderServiceSipImpl.throwOperationFailedException(
          "Failed to send the subscription", OperationFailedException.NETWORK_FAILURE, ex, logger);
    }
  }
    /** Refreshes the <tt>Subscription</tt> associated with this <tt>TimerTask</tt>. */
    @Override
    public void run() {
      Dialog dialog = subscription.getDialog();

      if (dialog == null) {
        logger.warn(
            "null dialog associated with " + subscription + ", can't refresh the subscription");
        return;
      }

      ClientTransaction transac = null;
      try {
        transac = createSubscription(subscription, dialog, subscriptionDuration);
      } catch (OperationFailedException e) {
        logger.error("Failed to create subscriptionTransaction.", e);
        return;
      }

      try {
        dialog.sendRequest(transac);
      } catch (SipException e) {
        logger.error("Can't send the request", e);
      }
    }
  /**
   * Creates and sends a SUBSCRIBE request to a specific subscription <tt>Address</tt>/Request URI
   * if it matches a <tt>Subscription</tt> with an id tag of its Event header of a specific value in
   * the list of subscriptions managed by this instance with an Expires header value of zero in
   * order to terminate receiving event notifications and removes the specified
   * <tt>Subscription</tt> from the list of subscriptions managed by this instance. The removed
   * <tt>Subscription</tt> may receive notifications to process the <tt>Request</tt>s and/or
   * <tt>Response</tt>s which constitute the signaling session associated with it. If the attempt to
   * create the SUBSCRIBE request fails, the associated <tt>Subscription</tt> is not removed from
   * the list of subscriptions managed by this instance. If the specified <tt>Address</tt> does not
   * identify an existing <tt>Subscription</tt> in the list of subscriptions managed by this
   * instance, an assertion may optionally be performed or no reaction can be taken.
   *
   * @param toAddress a subscription <tt>Address</tt>/Request URI which identifies a
   *     <tt>Subscription</tt> to be removed from the list of subscriptions managed by this instance
   * @param eventId the id tag placed in the Event header of the <tt>Subscription</tt> to be matched
   *     if there is one or <tt>null</tt> if the <tt>Subscription</tt> should have no id tag in its
   *     Event header
   * @param assertSubscribed <tt>true</tt> to assert if the specified subscription
   *     <tt>Address</tt>/Request URI does not identify an existing <tt>Subscription</tt> in the
   *     list of subscriptions managed by this instance; <tt>false</tt> to not assert if the
   *     mentioned condition is met
   * @throws IllegalArgumentException if <tt>assertSubscribed</tt> is <tt>true</tt> and
   *     <tt>toAddress</tt> and <tt>eventId</tt> do not identify an existing <tt>Subscription</tt>
   *     in the list of subscriptions managed by this instance
   * @throws OperationFailedException if we fail constructing or sending the unSUBSCRIBE request.
   */
  public void unsubscribe(Address toAddress, String eventId, boolean assertSubscribed)
      throws IllegalArgumentException, OperationFailedException {
    Subscription subscription = getSubscription(toAddress, eventId);
    if (subscription == null)
      if (assertSubscribed)
        throw new IllegalArgumentException("trying to unregister a not registered contact");
      else return;

    Dialog dialog = subscription.getDialog();

    // we stop the subscription if we're subscribed to this contact
    if (dialog != null) {
      String callId = dialog.getCallId().getCallId();

      ClientTransaction subscribeTransaction;
      try {
        subscribeTransaction = createSubscription(subscription, dialog, 0);
      } catch (OperationFailedException e) {
        if (logger.isDebugEnabled()) logger.debug("failed to create the unsubscription", e);
        throw e;
      }

      // we are not anymore subscribed to this contact
      // this ensure that the response of this request will be
      // handled as an unsubscription response
      removeSubscription(callId, subscription);

      try {
        dialog.sendRequest(subscribeTransaction);
      } catch (SipException e) {
        if (logger.isDebugEnabled()) logger.debug("Can't send the request", e);
        throw new OperationFailedException(
            "Failed to send the subscription message", OperationFailedException.NETWORK_FAILURE, e);
      }
    }
  }