Source Code Cross Referenced for Dialog.java in  » 6.0-JDK-Modules » j2me » gov » nist » siplite » stack » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » gov.nist.siplite.stack 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
0003:         * Reserved.  Use is subject to license terms.
0004:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0005:         * 
0006:         * This program is free software; you can redistribute it and/or
0007:         * modify it under the terms of the GNU General Public License version
0008:         * 2 only, as published by the Free Software Foundation.
0009:         * 
0010:         * This program is distributed in the hope that it will be useful, but
0011:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013:         * General Public License version 2 for more details (a copy is
0014:         * included at /legal/license.txt).
0015:         * 
0016:         * You should have received a copy of the GNU General Public License
0017:         * version 2 along with this work; if not, write to the Free Software
0018:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0019:         * 02110-1301 USA
0020:         * 
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0022:         * Clara, CA 95054 or visit www.sun.com if you need additional
0023:         * information or have any questions.
0024:         */
0025:        /*
0026:         */
0027:        package gov.nist.siplite.stack;
0028:
0029:        import java.util.*;
0030:        import gov.nist.siplite.header.*;
0031:        import gov.nist.siplite.address.*;
0032:        import gov.nist.siplite.message.*;
0033:        import gov.nist.siplite.*;
0034:        import gov.nist.core.*;
0035:        import java.io.IOException;
0036:        import javax.microedition.sip.SipException;
0037:
0038:        import com.sun.midp.log.Logging;
0039:        import com.sun.midp.log.LogChannels;
0040:
0041:        /**
0042:         * Tracks dialogs. A dialog is a peer to peer association of communicating
0043:         * SIP entities. For INVITE transactions, a Dialog is created when a success
0044:         * message is received (i.e. a response that has a ToHeader tag).
0045:         * The SIP Protocol stores enough state in the
0046:         * message structure to extract a dialog identifier that can be used to
0047:         * retrieve this structure from the SipStack.
0048:         *
0049:         * @version JAIN-SIP-1.1
0050:         *
0051:         * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
0052:         *
0053:         */
0054:        public class Dialog {
0055:            /** Opaque pointer to application data. */
0056:            private Object applicationData;
0057:            /** First transaction. */
0058:            private Transaction firstTransaction;
0059:            /** Last transaction. */
0060:            private Transaction lastTransaction;
0061:            /** Dialog identifier. */
0062:            private String dialogId;
0063:            /** Local sequence number. */
0064:            private int localSequenceNumber;
0065:            /** Remote sequence number. */
0066:            private int remoteSequenceNumber;
0067:            /** Local tag. */
0068:            private String myTag;
0069:            /** Remote tag. */
0070:            private String hisTag;
0071:            /** Route list. */
0072:            private RouteList routeList;
0073:            /** Contact route. */
0074:            private RouteHeader contactRoute;
0075:            /** User name. */
0076:            private String user;
0077:            /** Default route. */
0078:            private RouteHeader defaultRoute;
0079:            /** Current context SIP stack. */
0080:            private SIPTransactionStack sipStack;
0081:            /** Current Dialog state. */
0082:            private int dialogState;
0083:            /** ACK has been processed. */
0084:            protected boolean ackSeen;
0085:            /** Previous ACk. */
0086:            protected Request lastAck;
0087:            /** List of active subscriptions. */
0088:            public SubscriptionList subscriptionList;
0089:            /** Time remaining for retransmit. */
0090:            private int retransmissionTicksLeft;
0091:            /** Time used on previous retransmit. */
0092:            private int prevRetransmissionTicks;
0093:            /** Initial state. */
0094:            public final static int INITIAL_STATE = -1;
0095:            /** Early state. */
0096:            public final static int EARLY_STATE = 1;
0097:            /** Confirmed state. */
0098:            public final static int CONFIRMED_STATE = 2;
0099:            /** Completed state. */
0100:            public final static int COMPLETED_STATE = 3;
0101:            /** Terminated state. */
0102:            public final static int TERMINATED_STATE = 4;
0103:
0104:            /**
0105:             * Sets the pointer to application data.
0106:             * @param applicationData the new application data
0107:             */
0108:            public void setApplicationData(Object applicationData) {
0109:                this .applicationData = applicationData;
0110:            }
0111:
0112:            /**
0113:             * Gets pointer to opaque application data.
0114:             * @return application data
0115:             */
0116:            public Object getApplicationData() {
0117:                return this .applicationData;
0118:            }
0119:
0120:            /**
0121:             * A debugging print routine.
0122:             */
0123:            private void printRouteList() {
0124:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0125:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0126:                            "this : " + this );
0127:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0128:                            "printRouteList : " + this .routeList.encode());
0129:
0130:                    if (this .contactRoute != null) {
0131:                        Logging.report(Logging.INFORMATION,
0132:                                LogChannels.LC_JSR180, "contactRoute : "
0133:                                        + this .contactRoute.encode());
0134:                    } else {
0135:                        Logging.report(Logging.INFORMATION,
0136:                                LogChannels.LC_JSR180, "contactRoute : null");
0137:                    }
0138:                }
0139:            }
0140:
0141:            /**
0142:             * Gets the next hop.
0143:             * @return the next hop
0144:             * @exception SipException if an error occurs
0145:             */
0146:            public Hop getNextHop() throws SipException {
0147:                // This is already an established dialog so dont consult the router.
0148:                // Route the request based on the request URI.
0149:                RouteList rl = this .getRouteList();
0150:                SipURI sipUri = null;
0151:                String transport;
0152:
0153:                if (rl != null && !rl.isEmpty()) {
0154:                    RouteHeader route = (RouteHeader) rl.getFirst();
0155:                    sipUri = (SipURI) (route.getAddress().getURI());
0156:                    transport = route.getAddress().getParameter(
0157:                            SIPConstants.GENERAL_TRANSPORT);
0158:                } else if (contactRoute != null) {
0159:                    sipUri = (SipURI) (contactRoute.getAddress().getURI());
0160:                    transport = contactRoute.getAddress().getParameter(
0161:                            SIPConstants.GENERAL_TRANSPORT);
0162:                } else {
0163:                    throw new SipException("No route found!",
0164:                            SipException.GENERAL_ERROR);
0165:                }
0166:
0167:                String host = sipUri.getHost();
0168:                int port = sipUri.getPort();
0169:
0170:                if (port == -1) {
0171:                    port = SIPConstants.DEFAULT_NONTLS_PORT;
0172:                }
0173:
0174:                if (transport == null) {
0175:                    transport = SIPConstants.TRANSPORT_UDP;
0176:                }
0177:
0178:                return new Hop(host, port, transport);
0179:            }
0180:
0181:            /**
0182:             * Returns true if this is a client dialog.
0183:             *
0184:             * @return true if the transaction that created this dialog is a
0185:             *client transaction and false otherwise.
0186:             */
0187:            public boolean isClientDialog() {
0188:                Transaction transaction = (Transaction) getFirstTransaction();
0189:                return transaction instanceof  ClientTransaction;
0190:            }
0191:
0192:            /**
0193:             * Sets the state for this dialog.
0194:             *
0195:             * @param state is the state to set for the dialog.
0196:             */
0197:            public void setState(int state) {
0198:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0199:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0200:                            "Setting dialog state for " + this );
0201:                    // new Exception().printStackTrace();
0202:
0203:                    if (state != INITIAL_STATE && state != this .dialogState) {
0204:                        Logging.report(Logging.INFORMATION,
0205:                                LogChannels.LC_JSR180, "New dialog state is "
0206:                                        + state + "dialogId = "
0207:                                        + this .getDialogId());
0208:                    }
0209:
0210:                }
0211:
0212:                this .dialogState = state;
0213:            }
0214:
0215:            /**
0216:             * Debugging print for the dialog.
0217:             */
0218:            public void printTags() {
0219:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0220:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0221:                            "isServer = " + isServer());
0222:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0223:                            "localTag = " + getLocalTag());
0224:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0225:                            "remoteTag = " + getRemoteTag());
0226:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0227:                            "firstTransaction = "
0228:                                    + ((Transaction) firstTransaction)
0229:                                            .getOriginalRequest());
0230:                }
0231:            }
0232:
0233:            /**
0234:             * Marks that the dialog has seen an ACK.
0235:             * @param sipRequest the current SIP transaction
0236:             */
0237:            public void ackReceived(Request sipRequest) {
0238:                if (isServer()) {
0239:                    ServerTransaction st = (ServerTransaction) getFirstTransaction();
0240:                    if (st == null) {
0241:                        return;
0242:                    }
0243:
0244:                    // Suppress retransmission of the final response (in case
0245:                    // retransmission filter is being used).
0246:                    if (st.getOriginalRequest().getCSeqHeader()
0247:                            .getSequenceNumber() == sipRequest.getCSeqHeader()
0248:                            .getSequenceNumber()) {
0249:                        st.setState(Transaction.TERMINATED_STATE);
0250:                        ackSeen = true;
0251:                        lastAck = sipRequest;
0252:                    }
0253:                }
0254:            }
0255:
0256:            /**
0257:             * Returns true if the dialog has been acked. The ack is sent up to the
0258:             * TU exactly once when retransmission filter is enabled.
0259:             * @return true if ACK has been processed
0260:             */
0261:            public boolean isAckSeen() {
0262:                return this .ackSeen;
0263:            }
0264:
0265:            /**
0266:             * Gets the last ACK.
0267:             * @return the last ack
0268:             */
0269:            public Request getLastAck() {
0270:                return this .lastAck;
0271:            }
0272:
0273:            /**
0274:             * Gets the transaction that created this dialog.
0275:             * @return the first transaction
0276:             */
0277:            public Transaction getFirstTransaction() {
0278:                return firstTransaction;
0279:            }
0280:
0281:            /**
0282:             * Gets the route set for the dialog.
0283:             * When acting as an User Agent Server
0284:             * the route set MUST be set to the list of URIs in the
0285:             * Record-Route header field from the request, taken in order and
0286:             * preserving all URI parameters. When acting as an User Agent
0287:             * Client the route set MUST be set to the list of URIs in the
0288:             * Record-Route header field from the response, taken in
0289:             * reverse order and preserving all URI parameters. If no Record-Route
0290:             * header field is present in the request or response,
0291:             * the route set MUST be set to the empty set. This route set,
0292:             * even if empty, overrides any
0293:             * pre-existing route set for future requests in this dialog.
0294:             * <p>
0295:             * Requests within a dialog MAY contain Record-Route
0296:             * and Contact header fields.
0297:             * However, these requests do not cause the dialog's route set to be
0298:             * modified.
0299:             * <p>
0300:             * The User Agent Client uses the remote target
0301:             * and route set to build the
0302:             * Request-URI and Route header field of the request.
0303:             *
0304:             * @return an Iterator containing a list of route headers to be used for
0305:             * forwarding. Empty iterator is returned if route has not
0306:             * been established.
0307:             */
0308:            public Enumeration getRouteSet() {
0309:                if (this .routeList == null)
0310:                    return null;
0311:                else
0312:                    return this .getRouteList().getElements();
0313:            }
0314:
0315:            /**
0316:             * Gets the route list.
0317:             * @return the route list
0318:             */
0319:            private RouteList getRouteList() {
0320:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0321:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0322:                            "getRouteList " + this .getDialogId());
0323:                }
0324:
0325:                // Find the top via in the route list.
0326:                Vector li = routeList.getHeaders();
0327:                RouteList retval = new RouteList();
0328:
0329:                // If I am a UA then I am not record routing the request.
0330:
0331:                retval = new RouteList();
0332:
0333:                for (int i = 0; i < li.size(); i++) {
0334:                    RouteHeader route = (RouteHeader) li.elementAt(i);
0335:                    retval.add(route.clone());
0336:                }
0337:
0338:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0339:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0340:                            "----->>> ");
0341:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0342:                            "getRouteList for " + this );
0343:
0344:                    if (retval != null) {
0345:                        Logging.report(Logging.INFORMATION,
0346:                                LogChannels.LC_JSR180, "RouteList = "
0347:                                        + retval.encode());
0348:                    }
0349:
0350:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0351:                            "myRouteList = " + routeList.encode());
0352:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0353:                            "----->>> ");
0354:                }
0355:
0356:                return retval;
0357:            }
0358:
0359:            /**
0360:             * Sets the stack address.
0361:             * Prevent us from routing messages to ourselves.
0362:             * @param sipStack the address of the SIP stack.
0363:             */
0364:            public void setStack(SIPTransactionStack sipStack) {
0365:                this .sipStack = sipStack;
0366:            }
0367:
0368:            /**
0369:             * Sets the default route (the default next hop for the proxy or
0370:             * the proxy address for the user agent).
0371:             *
0372:             * @param defaultRoute is the default route to set.
0373:             *
0374:             */
0375:            public void setDefaultRoute(RouteHeader defaultRoute) {
0376:                this .defaultRoute = (RouteHeader) defaultRoute.clone();
0377:                // addRoute(defaultRoute,false);
0378:            }
0379:
0380:            /**
0381:             * Sets the user name for the default route.
0382:             *
0383:             * @param user is the user name to set for the default route.
0384:             *
0385:             */
0386:            public void setUser(String user) {
0387:                this .user = user;
0388:            }
0389:
0390:            /**
0391:             * Adds a route list extracted from a record route list.
0392:             * If this is a server dialog then we assume that the record
0393:             * are added to the route list IN order. If this is a client
0394:             * dialog then we assume that the record route headers give us
0395:             * the route list to add in reverse order.
0396:             *
0397:             * @param recordRouteList -- the record route list from the incoming
0398:             * @param transport       -- the transport parameter
0399:             * message.
0400:             */
0401:            private void addRoute(RecordRouteList recordRouteList,
0402:                    String transport) {
0403:                if (this .isClientDialog()) {
0404:                    // This is a client dialog so we extract the record
0405:                    // route from the response and reverse its order to
0406:                    // careate a route list.
0407:                    this .routeList = new RouteList();
0408:                    // start at the end of the list and walk backwards
0409:                    Vector li = recordRouteList.getHeaders();
0410:                    for (int i = li.size() - 1; i >= 0; i--) {
0411:                        RecordRouteHeader rr = (RecordRouteHeader) li
0412:                                .elementAt(i);
0413:                        Address addr = (Address) rr.getAddress();
0414:                        RouteHeader route = new RouteHeader();
0415:                        route.setAddress((Address) (rr.getAddress()).clone());
0416:                        route.setParameters((NameValueList) rr.getParameters()
0417:                                .clone());
0418:                        setRouteTransport(route, transport);
0419:                        this .routeList.add(route);
0420:                    }
0421:                } else {
0422:                    // This is a server dialog. The top most record route
0423:                    // header is the one that is closest to us. We extract the
0424:                    // route list in the same order as the addresses in the
0425:                    // incoming request.
0426:                    this .routeList = new RouteList();
0427:                    Vector li = recordRouteList.getHeaders();
0428:                    for (int i = 0; i < li.size(); i++) {
0429:                        RecordRouteHeader rr = (RecordRouteHeader) li
0430:                                .elementAt(i);
0431:                        RouteHeader route = new RouteHeader();
0432:                        route.setAddress((Address) (rr.getAddress()).clone());
0433:                        route.setParameters((NameValueList) rr.getParameters()
0434:                                .clone());
0435:                        setRouteTransport(route, transport);
0436:                        routeList.add(route);
0437:                    }
0438:                }
0439:            }
0440:
0441:            /**
0442:             * Sets the transport parameter to route header.
0443:             *
0444:             * @param route the route header for setting transport param
0445:             * @param transport the name of transport param
0446:             *
0447:             */
0448:            private void setRouteTransport(RouteHeader route, String transport) {
0449:                if (route.getAddress().getParameter(
0450:                        SIPConstants.GENERAL_TRANSPORT) == null) {
0451:                    route.getAddress().setParameter(
0452:                            SIPConstants.GENERAL_TRANSPORT, transport);
0453:                }
0454:            }
0455:
0456:            /**
0457:             * Adds a route list extacted from the contact list of the incoming
0458:             * message.
0459:             *
0460:             * @param contactList contact list extracted from the incoming
0461:             * message.
0462:             * @param transport the transport parameter
0463:             *
0464:             */
0465:            private void addRoute(ContactList contactList, String transport) {
0466:                if (contactList.size() == 0)
0467:                    return;
0468:                ContactHeader contact = (ContactHeader) contactList.getFirst();
0469:                RouteHeader route = new RouteHeader();
0470:                route.setAddress((Address) ((Address) (contact.getAddress()))
0471:                        .clone());
0472:                setRouteTransport(route, transport);
0473:                this .contactRoute = route;
0474:            }
0475:
0476:            /**
0477:             * Extracts the route information from this SIP Message and
0478:             * add the relevant information to the route set.
0479:             * @param sipMessage is the SIP message for which we want
0480:             * to add the route.
0481:             */
0482:            public synchronized void addRoute(Message sipMessage) {
0483:                String method = sipMessage.getCSeqHeader().getMethod();
0484:
0485:                // cannot add route list after the dialog is initialized.
0486:                try {
0487:                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0488:                        Logging.report(Logging.INFORMATION,
0489:                                LogChannels.LC_JSR180,
0490:                                "addRoute: dialogState: " + this  + "state = "
0491:                                        + this .getState());
0492:                    }
0493:
0494:                    String transport = ((ViaHeader) (sipMessage.getViaHeaders()
0495:                            .getFirst())).getTransport();
0496:
0497:                    // UPDATE processing: change route according to contact list
0498:                    if (Request.UPDATE.equals(method)
0499:                            && ((this .dialogState == EARLY_STATE) || (this .dialogState == CONFIRMED_STATE))) {
0500:
0501:                        ContactList contactList = sipMessage
0502:                                .getContactHeaders();
0503:                        if (contactList != null) {
0504:                            this .addRoute(contactList, transport);
0505:                        }
0506:                        return;
0507:                    }
0508:
0509:                    if (this .dialogState == CONFIRMED_STATE
0510:                            || this .dialogState == COMPLETED_STATE
0511:                            || this .dialogState == TERMINATED_STATE) {
0512:                        return;
0513:                    }
0514:
0515:                    if (!isServer()) {
0516:                        // I am CLIENT dialog.
0517:                        if (sipMessage instanceof  Response) {
0518:                            Response sipResponse = (Response) sipMessage;
0519:                            if (sipResponse.getStatusCode() == 100) {
0520:                                // Do nothing for trying messages.
0521:                                return;
0522:                            }
0523:
0524:                            RecordRouteList rrlist = sipMessage
0525:                                    .getRecordRouteHeaders();
0526:
0527:                            // Add the route set from the incoming response in reverse
0528:                            // order
0529:                            if (rrlist != null) {
0530:                                this .addRoute(rrlist, transport);
0531:                            } else {
0532:                                // Set the rotue list to the last seen route list.
0533:                                this .routeList = new RouteList();
0534:                            }
0535:
0536:                            ContactList contactList = sipMessage
0537:                                    .getContactHeaders();
0538:                            if (contactList != null) {
0539:                                if (sipResponse.getStatusCode() / 100 == 2
0540:                                        && (dialogState == INITIAL_STATE || dialogState == EARLY_STATE)) {
0541:                                    ContactHeader contact = (ContactHeader) contactList
0542:                                            .getFirst();
0543:
0544:                                    if (contact != null) {
0545:                                        String newTransport = contact
0546:                                                .getAddress()
0547:                                                .getParameter(
0548:                                                        SIPConstants.GENERAL_TRANSPORT);
0549:                                        if (newTransport != null) {
0550:                                            transport = newTransport;
0551:                                        }
0552:                                    }
0553:                                }
0554:
0555:                                this .addRoute(contactList, transport);
0556:                            }
0557:                        }
0558:                    } else {
0559:                        if (sipMessage instanceof  Request) {
0560:                            // Incoming Request has the route list
0561:                            RecordRouteList rrlist = sipMessage
0562:                                    .getRecordRouteHeaders();
0563:                            // Add the route set from the incoming response in reverse
0564:                            // order
0565:                            if (rrlist != null) {
0566:
0567:                                this .addRoute(rrlist, transport);
0568:                            } else {
0569:                                // Set the rotue list to the last seen route list.
0570:                                this .routeList = new RouteList();
0571:                            }
0572:                            // put the contact header from the incoming request into
0573:                            // the route set.
0574:                            ContactList contactList = sipMessage
0575:                                    .getContactHeaders();
0576:                            if (contactList != null) {
0577:                                this .addRoute(contactList, transport);
0578:                            }
0579:                        }
0580:                    }
0581:                } finally {
0582:                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0583:                        // new Exception()printStackTrace();
0584:                        Logging.report(Logging.INFORMATION,
0585:                                LogChannels.LC_JSR180, "added a route = "
0586:                                        + routeList.encode()
0587:                                        + "contactRoute = " + contactRoute);
0588:                    }
0589:                }
0590:            }
0591:
0592:            /**
0593:             * Protected Dialog constructor.
0594:             */
0595:            private Dialog() {
0596:                subscriptionList = new SubscriptionList();
0597:                routeList = new RouteList();
0598:                dialogState = -1; // not yet initialized.
0599:                localSequenceNumber = 0;
0600:                remoteSequenceNumber = -1;
0601:            }
0602:
0603:            /**
0604:             * Sets the dialog identifier.
0605:             * @param newDialogId the new dialog identifier
0606:             */
0607:            public void setDialogId(String newDialogId) {
0608:                dialogId = newDialogId;
0609:            }
0610:
0611:            /**
0612:             * Constructor given the first transaction.
0613:             *
0614:             * @param transaction is the first transaction.
0615:             */
0616:            protected Dialog(Transaction transaction) {
0617:                this ();
0618:                addTransaction(transaction);
0619:            }
0620:
0621:            /**
0622:             * Create route set for request.
0623:             *
0624:             * @param request the input request
0625:             * @throws SipException if any occurs
0626:             */
0627:            private void buildRouteSet(Request request) throws SipException {
0628:                getLastTransaction().buildRouteSet(request);
0629:            }
0630:
0631:            /**
0632:             * Returns true if is server.
0633:             *
0634:             * @return true if is server transaction created this dialog.
0635:             */
0636:            public boolean isServer() {
0637:                return getFirstTransaction() instanceof  ServerTransaction;
0638:            }
0639:
0640:            /**
0641:             * Gets the id for this dialog.
0642:             *
0643:             * @return the string identifier for this dialog.
0644:             */
0645:            public String getDialogId() {
0646:                if (firstTransaction instanceof  ServerTransaction) {
0647:                    // if (true || dialogId == null) {
0648:                    Request sipRequest = (Request) ((ServerTransaction) firstTransaction)
0649:                            .getOriginalRequest();
0650:                    dialogId = sipRequest.getDialogId(true, myTag);
0651:                    // }
0652:                } else {
0653:                    // This is a client transaction. Compute the dialog id
0654:                    // from the tag we have assigned to the outgoing
0655:                    // response of the dialog creating transaction.
0656:                    if (firstTransaction != null
0657:                            && ((ClientTransaction) getFirstTransaction())
0658:                                    .getLastResponse() != null) {
0659:                        dialogId = ((ClientTransaction) getFirstTransaction())
0660:                                .getLastResponse().getDialogId(false, hisTag);
0661:                    }
0662:                }
0663:
0664:                return dialogId;
0665:            }
0666:
0667:            /**
0668:             * Adds a transaction record to the dialog.
0669:             *
0670:             * @param transaction is the transaction to add to the dialog.
0671:             */
0672:            public void addTransaction(Transaction transaction) {
0673:                Request sipRequest = (Request) transaction.getOriginalRequest();
0674:
0675:                // Processing a re-invite.
0676:                // IMPL_NOTE : handle the re-invite
0677:                // Set state to Completed if we are processing a
0678:                // BYE transaction for the dialog.
0679:                // Will be set to TERMINATED after the BYE
0680:                // transaction completes.
0681:
0682:                if (sipRequest.getMethod().equals(Request.BYE)) {
0683:                    this .setState(COMPLETED_STATE);
0684:                }
0685:
0686:                if (firstTransaction == null) {
0687:                    // Record the local and remote sequence
0688:                    // numbers and the from and to tags for future
0689:                    // use on this dialog.
0690:                    firstTransaction = transaction;
0691:                    // IMPL_NOTE : set the local and remote party
0692:                    if (transaction instanceof  ServerTransaction) {
0693:                        hisTag = sipRequest.getFromHeader().getTag();
0694:                        // My tag is assigned when sending response
0695:                    } else {
0696:                        setLocalSequenceNumber(sipRequest.getCSeqHeader()
0697:                                .getSequenceNumber());
0698:                        // his tag is known when receiving response
0699:                        myTag = sipRequest.getFromHeader().getTag();
0700:                        if (myTag == null) {
0701:                            throw new RuntimeException(
0702:                                    "bad message tag missing!");
0703:                        }
0704:                    }
0705:                } else {
0706:                    String origMethod = transaction.getOriginalRequest()
0707:                            .getMethod();
0708:                    if (origMethod.equals(Request.ACK)) {
0709:                        origMethod = Request.INVITE;
0710:                    }
0711:                    if (firstTransaction.getOriginalRequest().getMethod()
0712:                            .equals(origMethod)
0713:                            && (((firstTransaction instanceof  ServerTransaction) && (transaction instanceof  ClientTransaction)) || ((firstTransaction instanceof  ClientTransaction) && (transaction instanceof  ServerTransaction)))) {
0714:                        // Switch from client side to server side for re-invite
0715:                        // (put the other side on hold).
0716:
0717:                        firstTransaction = transaction;
0718:                    }
0719:                }
0720:
0721:                if (transaction instanceof  ServerTransaction) {
0722:                    setRemoteSequenceNumber(sipRequest.getCSeqHeader()
0723:                            .getSequenceNumber());
0724:                }
0725:
0726:                lastTransaction = transaction;
0727:
0728:                // set a back ptr in the incoming dialog.
0729:                transaction.setDialog(this );
0730:
0731:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0732:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0733:                            "Transaction Added " + this  + myTag + "/" + hisTag);
0734:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0735:                            "TID = " + transaction.getTransactionId() + "/"
0736:                                    + transaction.IsServerTransaction());
0737:                    // new Exception().printStackTrace();
0738:                }
0739:            }
0740:
0741:            /**
0742:             * Sets the remote tag.
0743:             *
0744:             * @param hisTag is the remote tag to set.
0745:             */
0746:            public void setRemoteTag(String hisTag) {
0747:                this .hisTag = hisTag;
0748:            }
0749:
0750:            /**
0751:             * Gets the last transaction from the dialog.
0752:             * @return last transaction
0753:             */
0754:            public Transaction getLastTransaction() {
0755:                return this .lastTransaction;
0756:            }
0757:
0758:            /**
0759:             * Sets the local sequece number for the dialog (defaults to 1 when
0760:             * the dialog is created).
0761:             *
0762:             * @param lCseq is the local cseq number.
0763:             *
0764:             */
0765:            protected void setLocalSequenceNumber(int lCseq) {
0766:                this .localSequenceNumber = lCseq;
0767:            }
0768:
0769:            /**
0770:             * Sets the remote sequence number for the dialog.
0771:             *
0772:             * @param rCseq is the remote cseq number.
0773:             *
0774:             */
0775:            protected void setRemoteSequenceNumber(int rCseq) {
0776:                this .remoteSequenceNumber = rCseq;
0777:            }
0778:
0779:            /**
0780:             * Increments the local CSeqHeader # for the dialog.
0781:             *
0782:             * @return the incremented local sequence number.
0783:             *
0784:             */
0785:            public int incrementLocalSequenceNumber() {
0786:                return ++this .localSequenceNumber;
0787:            }
0788:
0789:            /**
0790:             * Gets the remote sequence number (for cseq assignment of outgoing
0791:             * requests within this dialog).
0792:             *
0793:             * @return local sequence number.
0794:             */
0795:            public int getRemoteSequenceNumber() {
0796:                return this .remoteSequenceNumber;
0797:            }
0798:
0799:            /**
0800:             * Gets the local sequence number (for cseq assignment of outgoing
0801:             * requests within this dialog).
0802:             *
0803:             * @return local sequence number.
0804:             */
0805:            public int getLocalSequenceNumber() {
0806:                return this .localSequenceNumber;
0807:            }
0808:
0809:            /**
0810:             * Gets local identifier for the dialog.
0811:             * This is used in FromHeader header tag construction
0812:             * for all outgoing client transaction requests for
0813:             * this dialog and for all outgoing responses for this dialog.
0814:             * This is used in ToHeader tag constuction for all outgoing
0815:             * transactions when we are the server of the dialog.
0816:             * Use this when constucting ToHeader header tags for BYE requests
0817:             * when we are the server of the dialog.
0818:             *
0819:             * @return the local tag.
0820:             */
0821:            public String getLocalTag() {
0822:                return this .myTag;
0823:            }
0824:
0825:            /**
0826:             * Gets peer identifier identifier for the dialog.
0827:             * This is used in ToHeader header tag construction for all outgoing
0828:             * requests when we are the client of the dialog.
0829:             * This is used in FromHeader tag construction for all outgoing
0830:             * requests when we are the Server of the dialog. Use
0831:             * this when costructing FromHeader header Tags for BYE requests
0832:             * when we are the server of the dialog.
0833:             *
0834:             * @return the remote tag
0835:             * (note this is read from a response to an INVITE).
0836:             *
0837:             */
0838:            public String getRemoteTag() {
0839:                return hisTag;
0840:            }
0841:
0842:            /**
0843:             * Sets local tag for the transaction.
0844:             *
0845:             * @param mytag is the tag to use in FromHeader headers client
0846:             * transactions that belong to this dialog and for
0847:             * generating ToHeader tags for Server transaction requests that belong
0848:             * to this dialog.
0849:             */
0850:            public void setLocalTag(String mytag) {
0851:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0852:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0853:                            "set Local tag " + mytag + " " + this .dialogId);
0854:                    // new Exception().printStackTrace();
0855:                }
0856:
0857:                myTag = mytag;
0858:            }
0859:
0860:            /**
0861:             * Marks all the transactions in the dialog inactive and ready
0862:             * for garbage collection.
0863:             */
0864:            protected void deleteTransactions() {
0865:                firstTransaction = null;
0866:                lastTransaction = null;
0867:            }
0868:
0869:            /**
0870:             * This method will release all resources associated with this dialog
0871:             * that are tracked by the Provider. Further references to the dialog by
0872:             * incoming messages will result in a mismatch.
0873:             * Since dialog destruction is left reasonably open ended in RFC3261,
0874:             * this delete method is provided
0875:             * for future use and extension methods that do not require a BYE to
0876:             * terminate a dialogue. The basic case of the INVITE and all dialogues
0877:             * that we are aware of today it is expected that BYE requests will
0878:             * end the dialogue.
0879:             */
0880:            public void delete() {
0881:                // the reaper will get him later.
0882:                setState(TERMINATED_STATE);
0883:            }
0884:
0885:            /**
0886:             * Returns the Call-ID for this SipSession. This is the value of the
0887:             * Call-ID header for all messages belonging to this session.
0888:             *
0889:             * @return the Call-ID for this Dialogue
0890:             */
0891:            public CallIdHeader getCallId() {
0892:                Request sipRequest = ((Transaction) this .getFirstTransaction())
0893:                        .getOriginalRequest();
0894:                return sipRequest.getCallId();
0895:            }
0896:
0897:            /**
0898:             * Gets the local Address for this dialog.
0899:             *
0900:             * @return the address object of the local party.
0901:             */
0902:            public Address getLocalParty() {
0903:                Request sipRequest = ((Transaction) this .getFirstTransaction())
0904:                        .getOriginalRequest();
0905:                if (!isServer()) {
0906:                    return sipRequest.getFromHeader().getAddress();
0907:                } else {
0908:                    return sipRequest.getTo().getAddress();
0909:                }
0910:            }
0911:
0912:            /**
0913:             * Returns the Address identifying the remote party.
0914:             * This is the value of the ToHeader header of locally initiated
0915:             * requests in this dialogue when acting as an User Agent Client.
0916:             * <p>
0917:             * This is the value of the FromHeader header of recieved responses in this
0918:             * dialogue when acting as an User Agent Server.
0919:             *
0920:             * @return the address object of the remote party.
0921:             */
0922:            public Address getRemoteParty() {
0923:                Request sipRequest = ((Transaction) this .getFirstTransaction())
0924:                        .getOriginalRequest();
0925:                if (!isServer()) {
0926:                    return sipRequest.getTo().getAddress();
0927:                } else {
0928:                    return sipRequest.getFromHeader().getAddress();
0929:                }
0930:            }
0931:
0932:            /**
0933:             * Returns the Address identifying the remote target.
0934:             * This is the value of the Contact header of recieved Responses
0935:             * for Requests or refresh Requests
0936:             * in this dialogue when acting as an User Agent Client <p>
0937:             * This is the value of the Contact header of received Requests
0938:             * or refresh Requests in this dialogue when acting as an User
0939:             *
0940:             * @return the address object of the remote target.
0941:             */
0942:            public Address getRemoteTarget() {
0943:                if (contactRoute == null) {
0944:                    return null;
0945:                }
0946:                return contactRoute.getAddress();
0947:            }
0948:
0949:            /**
0950:             * Returns the current state of the dialogue. The states are as follows:
0951:             * <ul>
0952:             * <li> Early - A dialog is in the "early" state, which occurs when it is
0953:             * created when a provisional response is recieved to the INVITE Request.
0954:             * <li> Confirmed - A dialog transitions to the "confirmed" state when a 2xx
0955:             * final response is received to the INVITE Request.
0956:             * <li> Completed - A dialog transitions to the "completed" state when a BYE
0957:             * request is sent or received by the User Agent Client.
0958:             * <li> Terminated - A dialog transitions to the "terminated" state when it
0959:             * can be garbage collection.
0960:             * </ul>
0961:             * Independent of the method, if a request outside of a dialog generates a
0962:             * non-2xx final response, any early dialogs created through provisional
0963:             * responses to that request are terminated. If no response arrives at all
0964:             * on the early dialog, it also terminates.
0965:             *
0966:             * @return a DialogState determining the current state of the dialog.
0967:             */
0968:            public int getState() {
0969:                return this .dialogState;
0970:            }
0971:
0972:            /**
0973:             * Returns true if this Dialog is secure i.e. if the request arrived over
0974:             * TLS, and the Request-URI contained a SIPS URI, the "secure" flag is set
0975:             * to TRUE.
0976:             *
0977:             * @return <code>true</code> if this dialogue was established using a sips
0978:             * URI over TLS, and <code>false</code> otherwise.
0979:             */
0980:            public boolean isSecure() {
0981:                return Utils.equalsIgnoreCase(getFirstTransaction()
0982:                        .getRequest().getRequestURI().getScheme(),
0983:                        SIPConstants.SCHEME_SIPS);
0984:            }
0985:
0986:            /**
0987:             * Sends ACK Request to the remote party of this Dialogue.
0988:             *
0989:             * @param request the new ACK Request message to send.
0990:             * @throws SipException if implementation cannot send the ACK Request for
0991:             * any other reason
0992:             */
0993:            public void sendAck(Request request) throws SipException {
0994:                Request ackRequest = (Request) request;
0995:
0996:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0997:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
0998:                            "sendAck" + this );
0999:                }
1000:
1001:                if (isServer()) {
1002:                    throw new SipException("Cannot sendAck from "
1003:                            + "Server side of Dialog",
1004:                            SipException.DIALOG_UNAVAILABLE);
1005:                }
1006:
1007:                if (!ackRequest.getMethod().equals(Request.ACK)) {
1008:                    throw new SipException(
1009:                            "Bad request method -- should be ACK",
1010:                            SipException.INVALID_MESSAGE);
1011:                }
1012:
1013:                if (getState() == -1 || getState() == EARLY_STATE) {
1014:                    throw new SipException("Bad dialog state " + getState(),
1015:                            SipException.INVALID_STATE);
1016:                }
1017:
1018:                if (!((Transaction) getFirstTransaction()).getOriginalRequest()
1019:                        .getCallId().getCallId().equals(
1020:                                ((Request) request).getCallId().getCallId())) {
1021:                    throw new SipException("Bad call ID in request",
1022:                            SipException.INVALID_MESSAGE);
1023:                }
1024:
1025:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1026:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
1027:                            "setting from tag For outgoing ACK = "
1028:                                    + this .getLocalTag());
1029:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
1030:                            "setting ToHeader tag for outgoing ACK = "
1031:                                    + this .getRemoteTag());
1032:                }
1033:
1034:                if (this .getLocalTag() != null)
1035:                    ackRequest.getFromHeader().setTag(this .getLocalTag());
1036:                if (this .getRemoteTag() != null)
1037:                    ackRequest.getTo().setTag(this .getRemoteTag());
1038:
1039:                // Create the route request and set it appropriately.
1040:                // Note that we only need to worry about being on the client
1041:                // side of the request.
1042:                buildRouteSet(ackRequest);
1043:
1044:                Hop hop = getNextHop();
1045:
1046:                try {
1047:                    MessageChannel messageChannel = sipStack
1048:                            .createRawMessageChannel(hop);
1049:                    if (messageChannel == null) {
1050:                        // procedures of 8.1.2 and 12.2.1.1 of RFC3261 have
1051:                        // been tried but the resulting next hop cannot be
1052:                        // resolved (recall that the exception thrown is
1053:                        // caught and ignored in
1054:                        // SIPMessageStack.createMessageChannel() so we end
1055:                        // up here with a null messageChannel instead of the
1056:                        // exception handler below). All else failing, try
1057:                        // the outbound proxy in accordance with 8.1.2, in
1058:                        // particular: This ensures that outbound proxies
1059:                        // that do not add Record-Route header field values
1060:                        // will drop out of the path of subsequent requests.
1061:                        // It allows endpoints that cannot resolve the first
1062:                        // Route URI to delegate that task to an outbound
1063:                        // proxy.
1064:                        //
1065:                        // if one considers the 'first Route URI' of a
1066:                        // request constructed according to 12.2.1.1
1067:                        // to be the request URI when the route set is empty.
1068:                        Hop outboundProxy = sipStack.getRouter()
1069:                                .getOutboundProxy();
1070:                        if (outboundProxy == null) {
1071:                            throw new SipException("No route found!",
1072:                                    SipException.GENERAL_ERROR);
1073:                        }
1074:
1075:                        messageChannel = sipStack
1076:                                .createRawMessageChannel(outboundProxy);
1077:                    }
1078:                    // Wrap a client transaction around the raw message channel.
1079:                    ClientTransaction clientTransaction = (ClientTransaction) sipStack
1080:                            .createMessageChannel(messageChannel);
1081:                    clientTransaction.setOriginalRequest(ackRequest);
1082:                    clientTransaction.sendMessage((Message) ackRequest);
1083:                    // Do not retransmit the ACK so terminate the transaction
1084:                    // immediately.
1085:                    this .lastAck = ackRequest;
1086:                    clientTransaction.setState(Transaction.TERMINATED_STATE);
1087:                } catch (IOException ex) {
1088:                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
1089:                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
1090:                                "Exception occured: " + ex);
1091:                        // ex.printStackTrace();
1092:                    }
1093:
1094:                    throw new SipException("Cold not create message channel",
1095:                            SipException.GENERAL_ERROR);
1096:                }
1097:            }
1098:
1099:            /**
1100:             * Creates a new Request message based on the dialog creating request.
1101:             * This method should be used for but not limited to creating Bye's,
1102:             * Refer's and re-Invite's on the Dialog. The returned Request will be
1103:             * correctly formatted that is it will contain the correct
1104:             * CSeqHeader header,
1105:             * Route headers and requestURI (derived from the remote target). This
1106:             * method should not be used for Ack, that is the application should
1107:             * create the Ack from the MessageFactory.
1108:             *
1109:             * If the route set is not empty, and the first URI in the route set
1110:             * contains the lr parameter (see Section 19.1.1), the UAC MUST place
1111:             * the remote target URI into the Request-URI and MUST include a Route
1112:             * header field containing the route set values in order, including all
1113:             * parameters.
1114:             * If the route set is not empty, and its first URI does not contain the
1115:             * lr parameter, the UAC MUST place the first URI from the route set
1116:             * into the Request-URI, stripping any parameters that are not allowed
1117:             * in a Request-URI. The UAC MUST add a Route header field containing
1118:             * the remainder of the route set values in order, including all
1119:             * parameters. The UAC MUST then place the remote target URI into the
1120:             * Route header field as the last value.
1121:             *
1122:             * @param method the string value that determines if the request to be
1123:             * created.
1124:             * @return the newly created Request message on this Dialog.
1125:             * @throws SipException if the Dialog is not yet established.
1126:             */
1127:            public Request createRequest(String method) throws SipException {
1128:                // Set the dialog back pointer.
1129:                if (method == null)
1130:                    throw new NullPointerException("null method");
1131:                else if (this .getState() == -1
1132:                        || ((!method.equals(Request.BYE)) && this .getState() == TERMINATED_STATE)
1133:                        || (method.equals(Request.BYE) && this .getState() == EARLY_STATE)) {
1134:                    throw new SipException(
1135:                            "Dialog not yet established or terminated",
1136:                            SipException.DIALOG_UNAVAILABLE);
1137:                }
1138:
1139:                Request originalRequest = (Request) getFirstTransaction()
1140:                        .getRequest();
1141:
1142:                RequestLine requestLine = new RequestLine();
1143:                requestLine.setUri((URI) getRemoteParty().getURI());
1144:                requestLine.setMethod(method);
1145:
1146:                Request sipRequest = originalRequest.createRequest(requestLine,
1147:                        isServer());
1148:
1149:                // Guess of local sequence number - this is being re-set when
1150:                // the request is actually dispatched (reported by Brad Templeton
1151:                // and Antonis Karydas).
1152:                if (!method.equals(Request.ACK)) {
1153:                    CSeqHeader cseq = (CSeqHeader) sipRequest.getCSeqHeader();
1154:                    cseq.setSequenceNumber(this .localSequenceNumber + 1);
1155:                }
1156:
1157:                if (isServer()) {
1158:                    // Remove the old via headers.
1159:                    sipRequest.removeHeader(Header.VIA);
1160:                    // Add a via header for the outbound request based on the
1161:                    // transport of the message processor.
1162:
1163:                    // MessageProcessor messageProcessor = sipStack.getMessageProcessor(
1164:                    //         firstTransaction.encapsulatedChannel.getTransport());
1165:                    MessageProcessor messageProcessor = firstTransaction.encapsulatedChannel
1166:                            .getMessageProcessor();
1167:
1168:                    ViaHeader via = messageProcessor.getViaHeader();
1169:                    sipRequest.addHeader(via);
1170:                }
1171:
1172:                FromHeader from = (FromHeader) sipRequest.getFromHeader();
1173:                ToHeader to = (ToHeader) sipRequest.getTo();
1174:
1175:                from.setTag(getLocalTag());
1176:                to.setTag(getRemoteTag());
1177:
1178:                // RFC 3261, p. 75:
1179:                // A UAC SHOULD include a Contact header field in any target refresh
1180:                // requests within a dialog, and unless there is a need to change it,
1181:                // the URI SHOULD be the same as used in previous requests within the
1182:                // dialog.
1183:                ContactList cl = originalRequest.getContactHeaders();
1184:                if (cl != null) {
1185:                    sipRequest.addHeader((ContactList) (cl.clone()));
1186:                }
1187:
1188:                // get the route list from the dialog.
1189:                buildRouteSet(sipRequest);
1190:
1191:                return sipRequest;
1192:            }
1193:
1194:            /**
1195:             * Sends a Request to the remote party of this dialog. This method
1196:             * implies that the application is functioning as UAC hence the
1197:             * underlying SipProvider acts statefully. This method is useful for
1198:             * sending Bye's for terminating a dialog or Re-Invites on the Dialog
1199:             * for third party call control.
1200:             * <p>
1201:             * This methods will set the FromHeader and the ToHeader tags for
1202:             * the outgoing
1203:             * request and also set the correct sequence number to the outgoing
1204:             * Request and associate the client transaction with this dialog.
1205:             * Note that any tags assigned by the user will be over-written by this
1206:             * method.
1207:             * <p>
1208:             * The User Agent must not send a BYE on a confirmed INVITE until it has
1209:             * received an ACK for its 2xx response or until the server transaction
1210:             * timeout is received.
1211:             * <p>
1212:             * When the retransmissionFilter is <code>true</code>,
1213:             * that is the SipProvider takes care of all retransmissions for the
1214:             * application, and the SipProvider can not deliver the Request after
1215:             * multiple retransmits the SipListener will be notified with a
1216:             * {@link TimeoutEvent} when the transaction expires.
1217:             * @param clientTransactionId the new ClientTransaction object identifying
1218:             * this transaction, this clientTransaction should be requested from
1219:             * SipProvider.getNewClientTransaction
1220:             * @throws TransactionDoesNotExistException if the serverTransaction does
1221:             * not correspond to any existing server transaction.
1222:             * @throws SipException if implementation cannot send the Request for
1223:             * any reason.
1224:             */
1225:            public void sendRequest(ClientTransaction clientTransactionId)
1226:                    throws SipException {
1227:                if (clientTransactionId == null) {
1228:                    throw new NullPointerException("null parameter");
1229:                }
1230:
1231:                Request dialogRequest = clientTransactionId
1232:                        .getOriginalRequest();
1233:                String method = dialogRequest.getMethod();
1234:
1235:                if (method.equals(Request.ACK) || method.equals(Request.CANCEL)) {
1236:                    throw new SipException("Bad Request Method: "
1237:                            + dialogRequest.getMethod(),
1238:                            SipException.INVALID_MESSAGE);
1239:                }
1240:
1241:                // Cannot send bye until the dialog has been established.
1242:                if (getState() == INITIAL_STATE) {
1243:                    throw new SipException("Bad dialog state (-1).",
1244:                            SipException.DIALOG_UNAVAILABLE);
1245:                }
1246:
1247:                if (Utils.equalsIgnoreCase(dialogRequest.getMethod(),
1248:                        Request.BYE)
1249:                        && getState() == EARLY_STATE) {
1250:                    throw new SipException("Bad dialog state ",
1251:                            SipException.DIALOG_UNAVAILABLE);
1252:                }
1253:
1254:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1255:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
1256:                            "dialog.sendRequest " + " dialog = " + this 
1257:                                    + "\ndialogRequest = \n" + dialogRequest);
1258:                }
1259:
1260:                if (dialogRequest.getTopmostVia() == null) {
1261:                    ViaHeader via = ((ClientTransaction) clientTransactionId)
1262:                            .getOutgoingViaHeader();
1263:                    dialogRequest.addHeader(via);
1264:                }
1265:
1266:                if (!((Transaction) this .getFirstTransaction())
1267:                        .getOriginalRequest().getCallId().getCallId().equals(
1268:                                dialogRequest.getCallId().getCallId())) {
1269:                    throw new SipException("Bad call ID in request",
1270:                            SipException.INVALID_MESSAGE);
1271:                }
1272:
1273:                // Set the dialog back pointer.
1274:                ((ClientTransaction) clientTransactionId).setDialog(this );
1275:
1276:                FromHeader from = (FromHeader) dialogRequest.getFromHeader();
1277:                ToHeader to = (ToHeader) dialogRequest.getTo();
1278:
1279:                from.setTag(this .getLocalTag());
1280:                to.setTag(this .getRemoteTag());
1281:
1282:                // Caller has not assigned the route header - set the route header
1283:                // and the request URI for the outgoing request.
1284:                // Bugs reported by Brad Templeton.
1285:
1286:                buildRouteSet(dialogRequest);
1287:
1288:                Hop hop = this .getNextHop();
1289:
1290:                try {
1291:                    MessageChannel messageChannel = sipStack
1292:                            .createRawMessageChannel(hop);
1293:                    ((ClientTransaction) clientTransactionId).encapsulatedChannel = messageChannel;
1294:
1295:                    if (messageChannel == null) {
1296:                        // procedures of 8.1.2 and 12.2.1.1 of RFC3261 have
1297:                        // been tried but the resulting next hop cannot be
1298:                        // resolved (recall that the exception thrown is
1299:                        // caught and ignored in
1300:                        // SIPMessageStack.createMessageChannel() so we end
1301:                        // up here with a null messageChannel instead of the
1302:                        // exception handler below). All else failing, try
1303:                        // the outbound proxy in accordance with 8.1.2, in
1304:                        // particular: This ensures that outbound proxies
1305:                        // that do not add Record-Route header field values
1306:                        // will drop out of the path of subsequent requests.
1307:                        // It allows endpoints that cannot resolve the first
1308:                        // Route URI to delegate that task to an outbound
1309:                        // proxy.
1310:                        //
1311:                        // if one considers the 'first Route URI' of a
1312:                        // request constructed according to 12.2.1.1
1313:                        // to be the request URI when the route set is empty.
1314:                        Hop outboundProxy = sipStack.getRouter()
1315:                                .getOutboundProxy();
1316:                        if (outboundProxy == null) {
1317:                            throw new SipException("No route found!",
1318:                                    SipException.GENERAL_ERROR);
1319:                        }
1320:                        messageChannel = sipStack
1321:                                .createRawMessageChannel(outboundProxy);
1322:                    }
1323:
1324:                    ((ClientTransaction) clientTransactionId).encapsulatedChannel = messageChannel;
1325:                } catch (IOException ex) {
1326:                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
1327:                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
1328:                                "Exception occured: " + ex);
1329:                    }
1330:
1331:                    throw new SipException("Could not create message channel.",
1332:                            SipException.GENERAL_ERROR);
1333:                }
1334:
1335:                // Increment before setting!!
1336:                localSequenceNumber++;
1337:                dialogRequest.getCSeqHeader().setSequenceNumber(
1338:                        getLocalSequenceNumber());
1339:
1340:                if (this .isServer()) {
1341:                    // ServerTransaction serverTransaction = (ServerTransaction)
1342:                    //     getFirstTransaction();
1343:
1344:                    from.setTag(this .myTag);
1345:                    to.setTag(this .hisTag);
1346:
1347:                    try {
1348:                        ((ClientTransaction) clientTransactionId)
1349:                                .sendMessage(dialogRequest);
1350:                        // If the method is BYE then mark the dialog completed.
1351:                        if (dialogRequest.getMethod().equals(Request.BYE)) {
1352:                            setState(COMPLETED_STATE);
1353:                        }
1354:                    } catch (IOException ex) {
1355:                        throw new SipException("Error sending message.",
1356:                                SipException.GENERAL_ERROR);
1357:                    }
1358:                } else {
1359:                    // I am the client so I do not swap headers.
1360:                    // ClientTransaction clientTransaction = (ClientTransaction)
1361:                    //     getFirstTransaction();
1362:
1363:                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1364:                        Logging.report(Logging.INFORMATION,
1365:                                LogChannels.LC_JSR180, "setting tags from "
1366:                                        + this .getDialogId());
1367:                        Logging.report(Logging.INFORMATION,
1368:                                LogChannels.LC_JSR180, "fromTag " + this .myTag);
1369:                        Logging.report(Logging.INFORMATION,
1370:                                LogChannels.LC_JSR180, "toTag " + this .hisTag);
1371:                    }
1372:
1373:                    from.setTag(this .myTag);
1374:                    to.setTag(this .hisTag);
1375:
1376:                    try {
1377:                        ((ClientTransaction) clientTransactionId)
1378:                                .sendMessage(dialogRequest);
1379:
1380:                        // If the method is BYE then mark the dialog completed.
1381:                        if (dialogRequest.getMethod().equals(Request.BYE)) {
1382:                            this .setState(COMPLETED_STATE);
1383:                        }
1384:                    } catch (IOException ex) {
1385:                        throw new SipException("Error sending message.",
1386:                                SipException.GENERAL_ERROR);
1387:                    }
1388:                }
1389:            }
1390:
1391:            /**
1392:             * Returns yes if the last response is to be retransmitted.
1393:             * @return true if final response retransmitted
1394:             */
1395:            protected boolean toRetransmitFinalResponse() {
1396:                if (--retransmissionTicksLeft == 0) {
1397:                    retransmissionTicksLeft = 2 * prevRetransmissionTicks;
1398:                    prevRetransmissionTicks = retransmissionTicksLeft;
1399:                    return true;
1400:                } else {
1401:                    return false;
1402:                }
1403:            }
1404:
1405:            /**
1406:             * Sets retransmission ticks.
1407:             */
1408:            protected void setRetransmissionTicks() {
1409:                retransmissionTicksLeft = 1;
1410:                prevRetransmissionTicks = 1;
1411:            }
1412:
1413:            /**
1414:             * Resends the last ack.
1415:             */
1416:            public void resendAck() {
1417:                // Check for null.
1418:                try {
1419:                    if (lastAck != null)
1420:                        sendAck(lastAck);
1421:                } catch (SipException ex) {
1422:                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
1423:                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
1424:                                "Dialog.resendAck(): SipException occured:"
1425:                                        + ex);
1426:                        ex.printStackTrace();
1427:                    }
1428:                }
1429:            }
1430:
1431:            /**
1432:             * Checks if this is an invitation dialog.
1433:             * @return true if this is an invitation dialog
1434:             */
1435:            public boolean isInviteDialog() {
1436:                return getFirstTransaction().getRequest().getMethod().equals(
1437:                        Request.INVITE);
1438:            }
1439:
1440:            /**
1441:             * Checks if this is a subscription dialog.
1442:             * @return true if this is a subscription dialog
1443:             */
1444:            public boolean isSubscribeDialog() {
1445:                String method = getFirstTransaction().getRequest().getMethod();
1446:                // REFER creates an implicit subscription
1447:                return (method.equals(Request.SUBSCRIBE) || method
1448:                        .equals(Request.REFER));
1449:            }
1450:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.