/**
   * Safely returns the transaction from the event if already exists. If not a new transaction is
   * created.
   *
   * @param event the request event
   * @return the server transaction
   * @throws javax.sip.TransactionAlreadyExistsException if transaction exists
   * @throws javax.sip.TransactionUnavailableException if unavailable
   */
  public static ServerTransaction getOrCreateServerTransaction(RequestEvent event)
      throws TransactionAlreadyExistsException, TransactionUnavailableException {
    ServerTransaction serverTransaction = event.getServerTransaction();

    if (serverTransaction == null) {
      SipProvider jainSipProvider = (SipProvider) event.getSource();

      serverTransaction = jainSipProvider.getNewServerTransaction(event.getRequest());
    }
    return serverTransaction;
  }
  /**
   * Dispatches the event received from a JAIN-SIP <tt>SipProvider</tt> to one of our "candidate
   * recipient" listeners.
   *
   * @param event the event received for a <tt>SipProvider</tt>.
   */
  public void processRequest(RequestEvent event) {
    try {
      Request request = event.getRequest();
      if (logger.isTraceEnabled()) logger.trace("received request: " + request.getMethod());

      /*
       * Create the transaction if it doesn't exist yet. If it is a
       * dialog-creating request, the dialog will also be automatically
       * created by the stack.
       */
      if (event.getServerTransaction() == null) {
        try {
          // apply some hacks if needed on incoming request
          // to be compliant with some servers/clients
          // if needed stop further processing.
          if (applyNonConformanceHacks(event)) return;

          SipProvider source = (SipProvider) event.getSource();
          ServerTransaction transaction = source.getNewServerTransaction(request);

          /*
           * Update the event, otherwise getServerTransaction() and
           * getDialog() will still return their previous value.
           */
          event = new RequestEvent(source, transaction, transaction.getDialog(), request);
        } catch (SipException ex) {
          logger.error(
              "couldn't create transaction, please report "
                  + "this to [email protected]",
              ex);
        }
      }

      ProtocolProviderServiceSipImpl service = getServiceData(event.getServerTransaction());
      if (service != null) {
        service.processRequest(event);
      } else {
        service = findTargetFor(request);
        if (service == null) {
          logger.error("couldn't find a ProtocolProviderServiceSipImpl " + "to dispatch to");
          if (event.getServerTransaction() != null) event.getServerTransaction().terminate();
        } else {

          /*
           * Mark the dialog for the dispatching of later in-dialog
           * requests. If there is no dialog, we need to mark the
           * request to dispatch a possible timeout when sending the
           * response.
           */
          Object container = event.getDialog();
          if (container == null) container = request;
          SipApplicationData.setApplicationData(container, SipApplicationData.KEY_SERVICE, service);

          service.processRequest(event);
        }
      }
    } catch (Throwable exc) {

      /*
       * Any exception thrown within our code should be caught here so
       * that we could log it rather than interrupt stack activity with
       * it.
       */
      this.logApplicationException(DialogTerminatedEvent.class, exc);

      // Unfortunately, death can hardly be ignored.
      if (exc instanceof ThreadDeath) throw (ThreadDeath) exc;
    }
  }