if ( LogWriter.needsLogging) sipStack.logWriter.logMessage("Hop = " + hop);
    public void sendAck(Request request) throws SipException {        SIPRequest ackRequest = (SIPRequest) request;        if (LogWriter.needsLogging)            sipStack.logWriter.logMessage("sendAck" + this);        // Loosen up check for re-invites (Andreas B)        // if (this.isServer())        //   throw new SipException        // ("Cannot sendAck from Server side of Dialog");        if (!ackRequest.getMethod().equals(Request.ACK)                && !ackRequest.getMethod().equals(Request.PRACK))            throw new SipException("Bad request method -- should be ACK");        if (ackRequest.getMethod().equals(Request.ACK)                && (this.getState() == null || this.getState().getValue() == EARLY_STATE)) {            throw new SipException("Bad dialog state " + this.getState());        } else if (ackRequest.getMethod().equals(Request.PRACK)                && this.getState() == null) {            throw new SipException("Bad dialog state sending PRACK"                    + this.getState());        }        // Set the dialog state to CONFIRMED when the Prack is sent        // out.        if (ackRequest.getMethod().equals(Request.PRACK)                && this.getState().getValue() == EARLY_STATE) {            this.setState(CONFIRMED_STATE);        }        if (!this.getCallId().getCallId().equals(                ((SIPRequest) request).getCallId().getCallId())) {            throw new SipException("Bad call ID in request");        }        try {            if (LogWriter.needsLogging) {                sipStack.logWriter                        .logMessage("setting from tag For outgoing ACK= "                                + this.getLocalTag());                sipStack.logWriter                        .logMessage("setting To tag for outgoing ACK = "                                + this.getRemoteTag());            }            if (this.getLocalTag() != null)                ackRequest.getFrom().setTag(this.getLocalTag());            if (this.getRemoteTag() != null)                ackRequest.getTo().setTag(this.getRemoteTag());        } catch (ParseException ex) {            throw new SipException(ex.getMessage());        }        // Create the route request and set it appropriately.        // Note that we only need to worry about being on the client        // side of the request.        if (ackRequest.getHeader(RouteHeader.NAME) == null) {            RouteList rl = this.getRouteList();            if (rl.size() > 0) {                Route route = (Route) rl.getFirst();                SipURI sipUri = (SipUri) route.getAddress().getURI();                if (sipUri.hasLrParam()) {                    ackRequest.setRequestURI(this.getRemoteTarget().getURI());                    ackRequest.addHeader(rl);                } else {                    // First route is not a lr                    // Add the contact route to the end.                    rl.removeFirst();                    ackRequest.setRequestURI(sipUri);                    // Bug report from Brad Templeton                    if (rl.size() > 0)                        ackRequest.addHeader(rl);                    if (contactRoute != null)                        ackRequest.addHeader(contactRoute);                }            } else {                if (this.getRemoteTarget() != null)                    ackRequest.setRequestURI(this.getRemoteTarget().getURI());            }        }        HopImpl hop = this.getNextHop();        try {            MessageChannel messageChannel = sipStack                    .createRawMessageChannel(this.firstTransaction.getPort(),hop);            if (messageChannel == null) {                // Bug fix from Antonis Karydas                // At this point the procedures of 8.1.2                // and 12.2.1.1 of RFC3261 have been tried                // but the resulting next hop cannot be resolved                // (recall that the exception thrown                // is caught and ignored in SIPStack.createMessageChannel()                // so we end up here with a null messageChannel                // instead of the exception handler below).                // All else failing, try the outbound proxy in accordance                // with 8.1.2, in particular:                // This ensures that outbound proxies that do not add                // Record-Route header field values will drop out of                // the path of subsequent requests. It allows endpoints                // that cannot resolve the first Route                // URI to delegate that task to an outbound proxy.                //                // if one considers the 'first Route URI' of a                // request constructed according to 12.2.1.1                // to be the request URI when the route set is empty.                Hop outboundProxy = sipStack.getRouter().getOutboundProxy();                if (outboundProxy == null)                    throw new SipException("No route found!");                messageChannel = sipStack                  .createRawMessageChannel(this.firstTransaction.getPort(), outboundProxy);            }            // Wrap a client transaction around the raw message channel.            SIPClientTransaction clientTransaction = (SIPClientTransaction) sipStack                    .createMessageChannel(messageChannel);            clientTransaction.setOriginalRequest(ackRequest);            clientTransaction.sendMessage((SIPMessage) ackRequest);            this.lastAck = ackRequest;            // Do not retransmit the ACK so terminate the transaction            // immediately.            clientTransaction.setState(SIPTransaction.TERMINATED_STATE);        } catch (Exception ex) {            if (LogWriter.needsLogging)                sipStack.logWriter.logException(ex);            throw new SipException("Cold not create message channel");        }    }