/** Initializes timeouts and listener. */
 void init(TransactionClientListener listener, TransactionIdentifier transaction_id) {
   this.transaction_listener = listener;
   this.transaction_id = transaction_id;
   retransmission_to = new Timer(SipStack.retransmission_timeout, "Retransmission", this);
   transaction_to = new Timer(SipStack.transaction_timeout, "Transaction", this);
   clearing_to = new Timer(SipStack.clearing_timeout, "Clearing", this);
   printLog("id: " + String.valueOf(transaction_id), LogLevel.HIGH);
   printLog("created", LogLevel.HIGH);
 }
 /**
  * Method derived from interface SipListener. It's fired from the SipProvider when a new message
  * is received for to the present TransactionClient.
  */
 public void onReceivedMessage(SipProvider provider, Message msg) {
   if (msg.isResponse()) {
     int code = msg.getStatusLine().getCode();
     if (code >= 100 && code < 200 && (statusIs(STATE_TRYING) || statusIs(STATE_PROCEEDING))) {
       if (statusIs(STATE_TRYING)) changeStatus(STATE_PROCEEDING);
       if (transaction_listener != null)
         transaction_listener.onTransProvisionalResponse(this, msg);
       return;
     }
     if (code >= 200 && code < 700 && (statusIs(STATE_TRYING) || statusIs(STATE_PROCEEDING))) {
       retransmission_to.halt();
       transaction_to.halt();
       changeStatus(STATE_COMPLETED);
       if (code < 300) {
         if (transaction_listener != null) transaction_listener.onTransSuccessResponse(this, msg);
       } else {
         if (transaction_listener != null) transaction_listener.onTransFailureResponse(this, msg);
       }
       transaction_listener = null;
       if (true || connection_id == null) // modified
       clearing_to.start();
       else {
         printLog("clearing_to=0 for reliable transport", LogLevel.LOW);
         onTimeout(clearing_to);
       }
       return;
     }
   }
 }
  /** Starts the TransactionClient and sends the transaction request. */
  public void request() {
    printLog("start", LogLevel.LOW);
    changeStatus(STATE_TRYING);
    retransmission_to.start();
    transaction_to.start();

    sip_provider.addSipProviderListener(transaction_id, this);
    connection_id = sip_provider.sendMessage(request);
  }
 /** Method derived from interface TimerListener. It's fired from an active Timer. */
 public void onTimeout(Timer to) {
   try {
     if (to.equals(retransmission_to) && (statusIs(STATE_TRYING) || statusIs(STATE_PROCEEDING))) {
       printLog("Retransmission timeout expired", LogLevel.HIGH);
       // retransmission only for unreliable transport
       if (true || connection_id == null) { // modified
         sip_provider.sendMessage(request);
         long timeout = 2 * retransmission_to.getTime();
         if (timeout > SipStack.max_retransmission_timeout || statusIs(STATE_PROCEEDING))
           timeout = SipStack.max_retransmission_timeout;
         retransmission_to = new Timer(timeout, retransmission_to.getLabel(), this);
         retransmission_to.start();
       } else
         printLog(
             "No retransmissions for reliable transport (" + connection_id + ")", LogLevel.LOW);
     }
     if (to.equals(transaction_to)) {
       printLog("Transaction timeout expired", LogLevel.HIGH);
       retransmission_to.halt();
       clearing_to.halt();
       sip_provider.removeSipProviderListener(transaction_id);
       changeStatus(STATE_TERMINATED);
       if (transaction_listener != null) transaction_listener.onTransTimeout(this);
       transaction_listener = null;
     }
     if (to.equals(clearing_to)) {
       printLog("Clearing timeout expired", LogLevel.HIGH);
       retransmission_to.halt();
       transaction_to.halt();
       sip_provider.removeSipProviderListener(transaction_id);
       changeStatus(STATE_TERMINATED);
     }
   } catch (Exception e) {
     printException(e, LogLevel.HIGH);
   }
 }