Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
   * Conditions Of Use
   *
   * This software was developed by employees of the National Institute of
   * Standards and Technology (NIST), and others.
   * This software is has been contributed to the public domain.
   * As a result, a formal license is not needed to use the software.
   *
   * This software is provided "AS IS."
  * NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
  * AND DATA ACCURACY.  NIST does not warrant or make any representations
  * regarding the use of the software or the results thereof, including but
  * not limited to the correctness, accuracy, reliability or usefulness of
  * the software.
  *
  *
  */
  package test.tck.msgflow;
  
  import  junit.framework.*;
  
  import javax.sip.*;
  import java.util.*;
  import java.text.*;
  import test.tck.*;

* The test tries to verify that Invite Server Transactions correctly change states as specified by the rfc3261. The Reference Implementation is used to send requests and a Tested Implementation ServerTransaction's states are queried and compared to those in the state machine described in section 17.2.1 of rfc3261

                              |INVITE
                              |pass INV to TU
            INVITE             V send 100 if TU won't in 200ms
            send response+-----------+
                +--------|           |--------+101-199 from TU
                |        | Proceeding|        |send response
                +------->|           |<-------+
                         |           |          Transport Err.
                         |           |          Inform TU
                         |           |--------------->+
                         +-----------+                |
            300-699 from TU |     |2xx from TU        |
            send response   |     |send response      |
                            |     +------------------>+
                            |                         |
            INVITE          V          Timer G fires  |
            send response+-----------+ send response  |
                +--------|           |--------+       |
                |        | Completed |        |       |
                +------->|           |<-------+       |
                         +-----------+                |
                            |     |                   |
                        ACK |     |                   |
                        -   |     +------------------>+
                            |        Timer H fires    |
                            V        or Transport Err.|
                         +-----------+  Inform TU     |
                         |           |                |
                         | Confirmed |                |
                         |           |                |
                         +-----------+                |
                               |                      |
                               |Timer I fires         |
                               |-                     |
                               |                      |
                               V                      |
                         +-----------+                |
                         |           |                |
                         | Terminated|<---------------+
                         |           |
                         +-----------+

              Figure 7: INVITE server transaction

Author(s):
Emil Ivov Network Research Team, Louis Pasteur University, Strasbourg, France. This code is in the public domain.
Version:
1.0
  
  
      extends MessageFlowHarness {
  
          super(name);
      }
  
     //==================== tests ==============================
     
Tries to steer a TI server transaction through the following scenario Proceeding-->Completed-->Confirmed-->Terminated. Apart from state transitions, we also test, retransmissions and proper hiding/passing of messages to the TU.
 
     public void testProceedingCompletedConfirmedScenario() {
         try {
             Request invite = createRiInviteRequest(nullnullnull);
             SipEventCollector responseCollector = new SipEventCollector();
             //Before Sending the request we should first register a listener with the
             //RI that would catch the TRYING response
             try {
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             //Send the initial request
             try {
                 .collectRequestEvent();
                 .sendRequest(invite);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent inviteReceivedEvent =
                 .extractCollectedRequestEvent();
             if (inviteReceivedEvent == null
                 || inviteReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The initial invite request was not received by the TI!");
             //Let's create the transaction
             ServerTransaction tran = null;
             try {
                 tran =
                     .getNewServerTransaction(
                         inviteReceivedEvent.getRequest());
             } catch (Exception ex) {
                 ex.printStackTrace();
                 fail(
                     ex.getClass().getName()
                         + "was thrown while trying to "
                         + "create the server transaction");
             }
             assertNotNull(
                 "tiSipProvider.getNewServerTransaction() returned null",
                 tran);
             //Check whether a TRYING response has been sent.
             //wait for the trying response
             waitForMessage();
             // At this point state must be PROCEEDING
             assertEquals(.tran.getState());
             ResponseEvent responseEvent =
                 responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No TRYING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from 100 was sent by the TI upon "
                     + "reception of INVITE",
                 . == responseEvent.getResponse().getStatusCode());
             //Resend the invite and see that a TRYING response is resent
             try {
                 //listen for the Trying response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 .collectRequestEvent();
                 .sendRequest(invite);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             //Wait for the INVITE
             waitForMessage();
             inviteReceivedEvent = .extractCollectedRequestEvent();
             assertNull(
                 "Retransmitted INVITEs should not be passed to the TU",
                 inviteReceivedEvent);
             //Wait for a retransmitted TRYING response
             waitForMessage();
             //Verify whether there was a TRYING response
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No TRYING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from 100 was sent by the TI upon "
                     + "reception of INVITE",
                 . == responseEvent.getResponse().getStatusCode());
 
             Response ringing = null;
             try {
                 ringing =
                     .createResponse(
                         .,
                         tran.getRequest());
                 ((ToHeaderringing.getHeader(.)).setTag(
                     Integer.toString(hashCode()));
                 addStatus(tran.getRequest(), ringing);
                 // BUG report from Ben Evans:
                 // set contact header on dialog-creating response
                 ringing.setHeader(createTiContact());
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a ringing "
                         + "response using TI",
                     ex);
             }
             //Create & send RINGING. See that it is properly sent
             //and that tran state doesn't change
             try {
                 //listen for the RINGING response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponse(ringing);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a RINGING response");
             }
             //The Transaction should still be PROCEEDING
             assertEquals(
                 "The Transaction did not remain PROCEEDING after transmitting a RINGING response",
                 .,
                 tran.getState());
            
           //Check whether the RINGING is received by the RI.
             waitForMessage();
 
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The RINGING response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from RINGING was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
             //Resend the INVITE, see that it is hidden from the TU and see that
             //the _RINGING_ response is resent (and not the TRYING)
             try {
                 //listen for the Trying response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 .collectRequestEvent();
                 .sendRequest(invite);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             //Wait for the INVITE
             waitForMessage();
             inviteReceivedEvent = .extractCollectedRequestEvent();
             assertNull(
                 "Retransmitted INVITEs should not be passed to the TU",
                 inviteReceivedEvent);
             //Wait for a retransmitted RINGING response
             waitForMessage();
             //Verify whether there was a RINGING response
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No RINGING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from RINGING was sent by the TI upon "
                     + "reception of a retransmitted invite INVITE",
                 .
                     == responseEvent.getResponse().getStatusCode());
             //We should still be proceeding
             assertEquals(
                 "The server transaction left the PROCEEDING state.",
                 .,
                 tran.getState());
             //Send 300 - 699 from TU and see the tran goes COMPLETED
             Response busy = null;
             try {
                 busy =
                     .createResponse(
                         .,
                         tran.getRequest());
                 addStatus(tran.getRequest(), busy);
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a busy_here "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the BUSY_HERE response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponse(busy);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a BUSY_HERE response");
             }
             //The Transaction should now be COMPLETED
             assertEquals(
                 "The Transaction did not remain COMPLETED after transmitting a BUSY_HERE response",
                 .,
                 tran.getState());
             //Check whether the BUSY_HERE is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The BUSY_HERE response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from BUSY_HERE was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
             //Resend the initial from INVITE from the RI and see that TI
             //resends the 300 - 699 (see that tran state remains COMPLETED)
             try {
                 //listen for the Trying response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 .collectRequestEvent();
                 .sendRequest(invite);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             //Wait for the INVITE
             waitForMessage();
             inviteReceivedEvent = .extractCollectedRequestEvent();
             assertNull(
                 "Retransmitted INVITEs should not be passed to the TU",
                 inviteReceivedEvent);
             //Wait for a retransmitted BUSY_HERE response
             waitForMessage();
             //Verify whether there was a BUSY_HERE response
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No BUSY_HERE response has been sent by the TI upon reception "
                     + "of a retransmitted INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from BUSY_HERE was sent by the TI upon "
                     + "reception of a retransmitted invite INVITE",
                 .
                     == responseEvent.getResponse().getStatusCode());
             //We should still be COMPLETED
             assertEquals(
                 "The server transaction left the COMPLETED state.",
                 .,
                 tran.getState());
             //Send an ack from the RI and see that the tran goes CONFIRMED
             //and that response retransmissions cease
             Request ack = (Requestinvite.clone();
             try {
                 .collectRequestEvent();
                 ack.setMethod(.);
 
                 // JvB: to tag must match response!
                 String toTag = ((ToHeaderresponseEvent.getResponse().getHeader("to")).getTag();
                 if (toTag!=null) {
                     ((ToHeaderack.getHeader("to")).setTagtoTag );
                 }
 
                 .sendRequest(ack);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with the TI provider",
                     ex);
             } catch (Exception ex) {
                 throw new TckInternalError(
                     "Failed to create an ack request",
                     ex);
             }
             waitForMessage();
             RequestEvent ackEvent =
                 .extractCollectedRequestEvent();
 
             assertNull(
                 "ACKs in ServerInviteTransactions shouldn't be passed to the TU.",
                 ackEvent);
             assertEquals(
                 "The ServerTransaction did not pas into the confirmed state"
                     + "after receiving an ACK.",
                 .,
                 tran.getState());
         } catch (Throwable exc) {
             exc.printStackTrace();
             fail(exc.getClass().getName() + ": " + exc.getMessage());
         }
         assertTrue(new Exception().getStackTrace()[0].toString(), true);
 
     }

    
JvB: tests CANCEL for an INVITE ST
 
     public void testCanceledInvite() {
         try {
             Request invite = createRiInviteRequest(nullnullnull);
             SipEventCollector responseCollector = new SipEventCollector();
             //Before Sending the request we should first register a listener with the
             //RI that would catch the TRYING response
             try {
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             //Send the initial request (JvB: using a CT)
             ClientTransaction riInviteCt;
             try {
                 .collectRequestEvent();
                 riInviteCt = .getNewClientTransactioninvite );
                 riInviteCt.sendRequest();
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent inviteReceivedEvent =
                 .extractCollectedRequestEvent();
             if (inviteReceivedEvent == null
                 || inviteReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The initial invite request was not received by the TI!");
             //Let's create the transaction
             ServerTransaction tran = null;
             try {
                 tran =
                     .getNewServerTransaction(
                         inviteReceivedEvent.getRequest());
             } catch (Exception ex) {
                 ex.printStackTrace();
                 fail(
                     ex.getClass().getName()
                         + "was thrown while trying to "
                         + "create the server transaction");
             }
             assertNotNull(
                 "tiSipProvider.getNewServerTransaction() returned null",
                 tran);
             //Check whether a TRYING response has been sent.
             //wait for the trying response
             waitForMessage();
             // At this point state must be PROCEEDING
             assertEquals(.tran.getState());
             ResponseEvent responseEvent =
                 responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No TRYING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from 100 was sent by the TI upon "
                     + "reception of INVITE",
                 . == responseEvent.getResponse().getStatusCode());
 
             //Create & send RINGING. See that it is properly sent
             //and that tran state doesn't change
             Response ringing = null;
             try {
                 ringing =
                     .createResponse(
                         .,
                         tran.getRequest());
                 ((ToHeaderringing.getHeader(.)).setTag(
                     Integer.toString(hashCode()));
                 addStatus(tran.getRequest(), ringing);
                 // BUG report from Ben Evans:
                 // set contact header on dialog-creating response
                 ringing.setHeader(createTiContact());
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a ringing "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the RINGING response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponse(ringing);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a RINGING response");
             }
             //The Transaction should still be PROCEEDING
             assertEquals(
                 "The Transaction did not remain PROCEEDING after transmitting a RINGING response",
                 .,
                 tran.getState());
             //Check whether the RINGING is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The RINGING response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from RINGING was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
 
             // JvB: *new* : send CANCEL here
             Request riCancel = riInviteCt.createCancel();
 
             // Send the CANCEL request
             try {
                 .collectRequestEvent();
                 .sendRequest(riCancel);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send CANCEL request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent cancelReceivedEvent = .extractCollectedRequestEvent();
             if (cancelReceivedEvent == null
                 || cancelReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The CANCEL request was not received by the TI!");
 
             // Check that a ST was matched, and that it is equal to the INVITE ST branch.
             assertEqualstran.getBranchId(), cancelReceivedEvent.getServerTransaction().getBranchId() );
 
             // Send an OK to the CANCEL
             Response cancelOK;
             try {
                 cancelOK =
                     .createResponse(
                         .cancelReceivedEvent.getRequest() );
                 addStatuscancelReceivedEvent.getRequest(), cancelOK );
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a OK "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the OK response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 cancelReceivedEvent.getServerTransaction().sendResponse(cancelOK);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a CANCEL OK response");
             }
 
             // Check whether the OK is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The CANCEL OK response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from OK was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
 
             //Send 487 from TU and see the tran goes COMPLETED
             Response reqTerminated = null;
             try {
                 reqTerminated =
                     .createResponse(
                         .,
                         tran.getRequest());
                 addStatus(tran.getRequest(), reqTerminated);
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a req_terminated "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the BUSY_HERE response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponsereqTerminated );
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a REQUEST_TERMINATED response");
             }
             //The Transaction should now be COMPLETED
             assertEquals(
                 "The Transaction did not remain COMPLETED after transmitting a REQUEST_TERMINATED response",
                 .,
                 tran.getState());
             //Check whether the BUSY_HERE is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The REQUEST_TERMINATED response was not received by the RI",
                 responseEvent);
             assertEquals(
                 "A response different from REQUEST_TERMINATED was sent by the TI",
                 .responseEvent.getResponse().getStatusCode() );
 
             // RI CT should have sent ACK, tran should be in CONFIRMED
             // and response retransmissions should cease
             assertEquals(
                 "The ServerTransaction did not pas into the confirmed state"
                     + "after receiving an ACK.",
                 .tran.getState());
         } catch (Throwable exc) {
             exc.printStackTrace();
             fail(exc.getClass().getName() + ": " + exc.getMessage());
         }
         assertTrue(new Exception().getStackTrace()[0].toString(), true);
 
     }

    
JvB: tests CANCEL for an INVITE ST, from an non-RFC3261 client which uses a Via branch not starting with the magic cookie
 
     public void testNonRFC3261CanceledInvite() {
         try {
             Request invite = createRiInviteRequest(nullnullnull);
 
             // JvB: Pretend it is sent by an older client
             ViaHeader topVia = (ViaHeaderinvite.getHeader"Via" );
             topVia.setBranch"non-rfc3261" );
 
             SipEventCollector responseCollector = new SipEventCollector();
             //Before Sending the request we should first register a listener with the
             //RI that would catch the TRYING response
             try {
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             //Send the initial request (JvB: using a CT)
             ClientTransaction riInviteCt;
             try {
                 .collectRequestEvent();
                 riInviteCt = .getNewClientTransactioninvite );
                 riInviteCt.sendRequest();
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent inviteReceivedEvent =
                 .extractCollectedRequestEvent();
             if (inviteReceivedEvent == null
                 || inviteReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The initial invite request was not received by the TI!");
             //Let's create the transaction
             ServerTransaction tran = null;
             try {
                 tran =
                     .getNewServerTransaction(
                         inviteReceivedEvent.getRequest());
             } catch (Exception ex) {
                 ex.printStackTrace();
                 fail(
                     ex.getClass().getName()
                         + "was thrown while trying to "
                         + "create the server transaction");
             }
             assertNotNull(
                 "tiSipProvider.getNewServerTransaction() returned null",
                 tran);
             //Check whether a TRYING response has been sent.
             //wait for the trying response
             waitForMessage();
             // At this point state must be PROCEEDING
             assertEquals(.tran.getState());
             ResponseEvent responseEvent =
                 responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No TRYING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from 100 was sent by the TI upon "
                     + "reception of INVITE",
                 . == responseEvent.getResponse().getStatusCode());
 
             //Create & send RINGING. See that it is properly sent
             //and that tran state doesn't change
             Response ringing = null;
             try {
                 ringing =
                     .createResponse(
                         .,
                         tran.getRequest());
                 ((ToHeaderringing.getHeader(.)).setTag(
                     Integer.toString(hashCode()));
                 addStatus(tran.getRequest(), ringing);
                 // BUG report from Ben Evans:
                 // set contact header on dialog-creating response
                 ringing.setHeader(createTiContact());
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a ringing "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the RINGING response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponse(ringing);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a RINGING response");
             }
             //The Transaction should still be PROCEEDING
             assertEquals(
                 "The Transaction did not remain PROCEEDING after transmitting a RINGING response",
                 .,
                 tran.getState());
             //Check whether the RINGING is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The RINGING response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from RINGING was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
 
             // JvB: *new* : send CANCEL here
             Request riCancel = riInviteCt.createCancel();
 
             // Send the CANCEL request
             try {
                 .collectRequestEvent();
                 .sendRequest(riCancel);
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send CANCEL request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent cancelReceivedEvent = .extractCollectedRequestEvent();
             if (cancelReceivedEvent == null
                 || cancelReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The CANCEL request was not received by the TI!");
 
             // Check that a ST was matched, and that it is equal to the INVITE ST
             assertEqualstran.getBranchId(), cancelReceivedEvent.getServerTransaction().getBranchId() );
 
             // Send an OK to the CANCEL
             Response cancelOK;
             try {
                 cancelOK =
                     .createResponse(
                         .cancelReceivedEvent.getRequest() );
                 addStatuscancelReceivedEvent.getRequest(), cancelOK );
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a OK "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the OK response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 // send it statelessly
                 cancelReceivedEvent.getServerTransaction().sendResponse(cancelOK);
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a CANCEL OK response");
             }
 
             // Check whether the OK is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The CANCEL OK response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from OK was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
 
             //Send 487 from TU and see the tran goes COMPLETED
             Response reqTerminated = null;
             try {
                 reqTerminated =
                     .createResponse(
                         .,
                         tran.getRequest());
                 addStatus(tran.getRequest(), reqTerminated);
             } catch (ParseException ex) {
                 throw new TiUnexpectedError(
                     "A ParseException was thrown while trying to create a req_terminated "
                         + "response using TI",
                     ex);
             }
             try {
                 //listen for the BUSY_HERE response
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             try {
                 tran.sendResponsereqTerminated );
             } catch (SipException ex) {
                 ex.printStackTrace();
                 fail("The TI failed to send a REQUEST_TERMINATED response");
             }
             //The Transaction should now be COMPLETED
             assertEquals(
                 "The Transaction did not remain COMPLETED after transmitting a REQUEST_TERMINATED response",
                 .,
                 tran.getState());
             //Check whether the BUSY_HERE is received by the RI.
             waitForMessage();
             responseEvent = responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "The REQUEST_TERMINATED response was not received by the RI",
                 responseEvent);
             assertTrue(
                 "A response different from REQUEST_TERMINATED was sent by the TI",
                 .
                     == responseEvent.getResponse().getStatusCode());
 
             // RI CT should have sent ACK, tran should be in CONFIRMED
             // and response retransmissions should cease
             assertEquals(
                 "The ServerTransaction did not pas into the confirmed state"
                     + "after receiving an ACK.",
                 .tran.getState());
         } catch (Throwable exc) {
             exc.printStackTrace();
             fail(exc.getClass().getName() + ": " + exc.getMessage());
         }
         assertTrue(new Exception().getStackTrace()[0].toString(), true);
 
     }

    
JvB: tests CANCEL for an INVITE ST, in case the client changes the case of the branch id to all lowercvase (NIST used to do this)
 
     public void testCaseInsensitiveCanceledInvite() {
         try {
             Request invite = createRiInviteRequest(nullnullnull);
             SipEventCollector responseCollector = new SipEventCollector();
             //Before Sending the request we should first register a listener with the
             //RI that would catch the TRYING response
             try {
                 responseCollector.collectResponseEvent();
             } catch (TooManyListenersException ex) {
                 throw new TckInternalError(
                     "Failed to register a SipListener with an RI SipProvider",
                     ex);
             }
             //Send the initial request (JvB: using a CT)
             ClientTransaction riInviteCt;
             try {
                 .collectRequestEvent();
                 riInviteCt = .getNewClientTransactioninvite );
                 riInviteCt.sendRequest();
             } catch (SipException ex) {
                 throw new TckInternalError(
                     "A SipExceptionOccurred while trying to send request!",
                     ex);
             } catch (TooManyListenersException ex) {
                 throw new TiUnexpectedError(
                     "Failed to register a SipListener with a TI SipProvider",
                     ex);
             }
             waitForMessage();
             RequestEvent inviteReceivedEvent =
                 .extractCollectedRequestEvent();
             if (inviteReceivedEvent == null
                 || inviteReceivedEvent.getRequest() == null)
                 throw new TiUnexpectedError("The initial invite request was not received by the TI!");
             //Let's create the transaction
             ServerTransaction tran = null;
             try {
                 tran =
                     .getNewServerTransaction(
                         inviteReceivedEvent.getRequest());
             } catch (Exception ex) {
                 ex.printStackTrace();
                 fail(
                     ex.getClass().getName()
                         + "was thrown while trying to "
                         + "create the server transaction");
             }
             assertNotNull(
                 "tiSipProvider.getNewServerTransaction() returned null",
                 tran);
             //Check whether a TRYING response has been sent.
             //wait for the trying response
             waitForMessage();
             // At this point state must be PROCEEDING
             assertEquals(.tran.getState());
             ResponseEvent responseEvent =
                 responseCollector.extractCollectedResponseEvent();
             assertNotNull(
                 "No TRYING response has been sent by the TI upon reception "
                     + "of an INVITE request",
                 responseEvent);
             assertTrue(
                 "A response different from 100 was sent by the TI upon "
                     + "reception of INVITE",
                 . == responseEvent.getResponse().getStatusCode());
 
             //Create & send RINGING. See that it is properly sent
             //and that tran state doesn't change
             Response ringing = null;
            try {
                ringing =
                    .createResponse(
                        .,
                        tran.getRequest());
                ((ToHeaderringing.getHeader(.)).setTag(
                    Integer.toString(hashCode()));
                addStatus(tran.getRequest(), ringing);
                // BUG report from Ben Evans:
                // set contact header on dialog-creating response
                ringing.setHeader(createTiContact());
            } catch (ParseException ex) {
                throw new TiUnexpectedError(
                    "A ParseException was thrown while trying to create a ringing "
                        + "response using TI",
                    ex);
            }
            try {
                //listen for the RINGING response
                responseCollector.collectResponseEvent();
            } catch (TooManyListenersException ex) {
                throw new TckInternalError(
                    "Failed to register a SipListener with an RI SipProvider",
                    ex);
            }
            try {
                tran.sendResponse(ringing);
            } catch (SipException ex) {
                ex.printStackTrace();
                fail("The TI failed to send a RINGING response");
            }
            //The Transaction should still be PROCEEDING
            assertEquals(
                "The Transaction did not remain PROCEEDING after transmitting a RINGING response",
                .,
                tran.getState());
            //Check whether the RINGING is received by the RI.
            waitForMessage();
            responseEvent = responseCollector.extractCollectedResponseEvent();
            assertNotNull(
                "The RINGING response was not received by the RI",
                responseEvent);
            assertTrue(
                "A response different from RINGING was sent by the TI",
                .
                    == responseEvent.getResponse().getStatusCode());
            // JvB: *new* : send CANCEL here
            Request riCancel = riInviteCt.createCancel();
            // Change Via branch to all lower case, clients SHOULD NOT
            // do this but stack should be able to handle this
            ViaHeader topVia = (ViaHeaderriCancel.getHeader("Via");
            topVia.setBranchtopVia.getBranch().toLowerCase() );
            // Send the CANCEL request
            try {
                .collectRequestEvent();
                .sendRequest(riCancel);
            } catch (SipException ex) {
                throw new TckInternalError(
                    "A SipExceptionOccurred while trying to send CANCEL request!",
                    ex);
            } catch (TooManyListenersException ex) {
                throw new TiUnexpectedError(
                    "Failed to register a SipListener with a TI SipProvider",
                    ex);
            }
            waitForMessage();
            RequestEvent cancelReceivedEvent = .extractCollectedRequestEvent();
            if (cancelReceivedEvent == null
                || cancelReceivedEvent.getRequest() == null)
                throw new TiUnexpectedError("The CANCEL request was not received by the TI!");
            // Check that a ST was matched, and that it is equal to the INVITE ST
            // mranga -- I dont know if its valid to do things this way!
            //assertSame( tran, cancelReceivedEvent.getServerTransaction() );
            // Send an OK to the CANCEL
            Response cancelOK;
            try {
                cancelOK =
                    .createResponse(
                        .cancelReceivedEvent.getRequest() );
                addStatuscancelReceivedEvent.getRequest(), cancelOK );
            } catch (ParseException ex) {
                throw new TiUnexpectedError(
                    "A ParseException was thrown while trying to create a OK "
                        + "response using TI",
                    ex);
            }
            try {
                //listen for the OK response
                responseCollector.collectResponseEvent();
            } catch (TooManyListenersException ex) {
                throw new TckInternalError(
                    "Failed to register a SipListener with an RI SipProvider",
                    ex);
            }
            try {
                cancelReceivedEvent.getServerTransaction().sendResponse(cancelOK);
            } catch (SipException ex) {
                ex.printStackTrace();
                fail("The TI failed to send a CANCEL OK response");
            }
            // Check whether the OK is received by the RI.
            waitForMessage();
            responseEvent = responseCollector.extractCollectedResponseEvent();
            assertNotNull(
                "The CANCEL OK response was not received by the RI",
                responseEvent);
            assertTrue(
                "A response different from OK was sent by the TI",
                .
                    == responseEvent.getResponse().getStatusCode());
            //Send 487 from TU and see the tran goes COMPLETED
            Response reqTerminated = null;
            try {
                reqTerminated =
                    .createResponse(
                        .,
                        tran.getRequest());
                addStatus(tran.getRequest(), reqTerminated);
            } catch (ParseException ex) {
                throw new TiUnexpectedError(
                    "A ParseException was thrown while trying to create a req_terminated "