Source Code Cross Referenced for ServerTransaction.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) 


001:        /*
002:         * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
003:         * Reserved.  Use is subject to license terms.
004:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005:         * 
006:         * This program is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU General Public License version
008:         * 2 only, as published by the Free Software Foundation.
009:         * 
010:         * This program is distributed in the hope that it will be useful, but
011:         * WITHOUT ANY WARRANTY; without even the implied warranty of
012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013:         * General Public License version 2 for more details (a copy is
014:         * included at /legal/license.txt).
015:         * 
016:         * You should have received a copy of the GNU General Public License
017:         * version 2 along with this work; if not, write to the Free Software
018:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019:         * 02110-1301 USA
020:         * 
021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022:         * Clara, CA 95054 or visit www.sun.com if you need additional
023:         * information or have any questions.
024:         */
025:        package gov.nist.siplite.stack;
026:
027:        import gov.nist.siplite.message.*;
028:        import gov.nist.siplite.header.*;
029:        import gov.nist.siplite.address.*;
030:        import gov.nist.core.*;
031:        import gov.nist.siplite.*;
032:
033:        import java.io.IOException;
034:        import javax.microedition.sip.SipException;
035:
036:        import com.sun.midp.log.Logging;
037:        import com.sun.midp.log.LogChannels;
038:
039:        /**
040:         * Represents a server transaction.
041:         *
042:         *
043:         * @version JAIN-SIP-1.1
044:         * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
045:         */
046:        public class ServerTransaction extends Transaction implements 
047:                SIPServerRequestInterface {
048:            /** Collection time. */
049:            protected int collectionTime;
050:            /** Real RequestInterface to pass messages to. */
051:            private SIPServerRequestInterface requestOf;
052:            /** Flag indicating this transaction is known to the stack. */
053:            protected boolean isMapped;
054:
055:            /**
056:             * Sends the SIP response.
057:             * @param transactionResponse the transaction response
058:             * @exception IOException if the response could not be sent
059:             */
060:            private void sendSIPResponse(Response transactionResponse)
061:                    throws IOException {
062:                if (transactionResponse.getTopmostVia().getParameter(
063:                        ViaHeader.RECEIVED) == null) {
064:                    // Send the response back on the same peer
065:                    // as received.
066:                    getMessageChannel().sendMessage(transactionResponse);
067:                } else {
068:                    // Respond to the host name in the received parameter.
069:                    ViaHeader via = transactionResponse.getTopmostVia();
070:                    String host = via.getParameter(ViaHeader.RECEIVED);
071:                    int port = via.getPort();
072:                    if (port == -1)
073:                        port = 5060;
074:                    String transport = via.getTransport();
075:                    Hop hop = new Hop(host + ":" + port + "/" + transport);
076:                    MessageChannel messageChannel = ((SIPTransactionStack) getSIPStack())
077:                            .createRawMessageChannel(hop);
078:                    messageChannel.sendMessage(transactionResponse);
079:                }
080:                this .lastResponse = transactionResponse;
081:            }
082:
083:            /**
084:             * Delays the sending of the Trying state.
085:             */
086:            class SendTrying extends Thread {
087:                /** Current server transaction. */
088:                ServerTransaction myTransaction;
089:
090:                /**
091:                 * Constructore with initial transaction.
092:                 * @param transaction the transaction to be sent
093:                 */
094:                public SendTrying(ServerTransaction transaction) {
095:                    myTransaction = transaction;
096:                    Thread myThread = new Thread(this );
097:                    myThread.start();
098:                }
099:
100:                /** Main loop for sending transaction asynchronously. */
101:                public void run() {
102:                    try {
103:                        Thread.sleep(200);
104:                    } catch (InterruptedException ex) {
105:                    }
106:
107:                    if (myTransaction.getState() == TRYING_STATE) {
108:                        try {
109:                            myTransaction.sendMessage(myTransaction
110:                                    .getOriginalRequest().createResponse(100,
111:                                            "Trying"));
112:                        } catch (IOException ex) {
113:                        }
114:                    }
115:                    return;
116:                }
117:            }
118:
119:            /**
120:             * Creates a new server transaction.
121:             *
122:             * @param newSIPMessageStack Transaction stack this transaction
123:             * belongs to.
124:             * @param newChannelToHeaderUse Channel to encapsulate.
125:             */
126:            protected ServerTransaction(SIPTransactionStack newSIPMessageStack,
127:                    MessageChannel newChannelToHeaderUse) {
128:                super (newSIPMessageStack, newChannelToHeaderUse);
129:
130:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
131:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
132:                            "Creating Server Transaction" + this );
133:                    // new Exception().printStackTrace();
134:                }
135:            }
136:
137:            /**
138:             * Sets the real RequestInterface this transaction encapsulates.
139:             *
140:             * @param newRequestOf RequestInterface to send messages to.
141:             */
142:            public void setRequestInterface(
143:                    SIPServerRequestInterface newRequestOf) {
144:                requestOf = newRequestOf;
145:            }
146:
147:            /**
148:             * Gets the processing infromation.
149:             * @return the processing information
150:             */
151:            public String getProcessingInfo() {
152:                return requestOf.getProcessingInfo();
153:            }
154:
155:            /**
156:             * Deterines if the message is a part of this transaction.
157:             *
158:             * @param messageToHeaderTest Message to check if it is part of this
159:             * transaction.
160:             *
161:             * @return True if the message is part of this transaction,
162:             * false if not.
163:             */
164:            public boolean isMessagePartOfTransaction(
165:                    Message messageToHeaderTest) {
166:                // List of Via headers in the message to test
167:                ViaList viaHeaders;
168:                // ToHeaderpmost Via header in the list
169:                ViaHeader topViaHeader;
170:                // Branch code in the topmost Via header
171:                String messageBranch;
172:                // Flags whether the select message is part of this transaction
173:                boolean transactionMatches;
174:
175:                transactionMatches = false;
176:                // Compensation for retransmits after OK has been dispatched
177:                // as suggested by Antonis Karydas.
178:                if ((((SIPTransactionStack) getSIPStack())
179:                        .isDialogCreated(((Request) messageToHeaderTest)
180:                                .getMethod()))
181:                        || !isTerminated()) {
182:                    // Get the topmost Via header and its branch parameter
183:                    viaHeaders = messageToHeaderTest.getViaHeaders();
184:                    if (viaHeaders != null) {
185:                        topViaHeader = (ViaHeader) viaHeaders.getFirst();
186:                        messageBranch = topViaHeader.getBranch();
187:                        if (messageBranch != null) {
188:                            // If the branch parameter exists but
189:                            // does not start with the magic cookie,
190:                            if (!messageBranch.toUpperCase().startsWith(
191:                                    SIPConstants.GENERAL_BRANCH_MAGIC_COOKIE
192:                                            .toUpperCase())) {
193:                                // Flags this as old
194:                                // (RFC2543-compatible) client
195:                                // version
196:                                messageBranch = null;
197:                            }
198:                        }
199:                        // If a new branch parameter exists,
200:                        if (messageBranch != null && this .getBranch() != null) {
201:                            if (getBranch().equals(messageBranch)
202:                                    && topViaHeader
203:                                            .getSentBy()
204:                                            .equals(
205:                                                    ((ViaHeader) getOriginalRequest()
206:                                                            .getViaHeaders()
207:                                                            .getFirst())
208:                                                            .getSentBy())) {
209:                                // Matching server side transaction with only the
210:                                // branch parameter.
211:                                transactionMatches = true;
212:                            }
213:                            // If this is an RFC2543-compliant message,
214:                        } else {
215:
216:                            // If RequestURI, ToHeader tag, FromHeader tag,
217:                            // CallIdHeader, CSeqHeader number, and top Via
218:                            // headers are the same,
219:                            String originalFromHeaderTag = getOriginalRequest()
220:                                    .getFromHeader().getTag();
221:                            String this FromHeaderTag = messageToHeaderTest
222:                                    .getFromHeader().getTag();
223:                            boolean skipFromHeader = (originalFromHeaderTag == null || this FromHeaderTag == null);
224:                            String originalToHeaderTag = getOriginalRequest()
225:                                    .getTo().getTag();
226:                            String this ToHeaderTag = messageToHeaderTest
227:                                    .getTo().getTag();
228:                            boolean skipToHeader = (originalToHeaderTag == null || this ToHeaderTag == null);
229:                            if (getOriginalRequest().getRequestURI().equals(
230:                                    ((Request) messageToHeaderTest)
231:                                            .getRequestURI())
232:                                    && (skipFromHeader || originalFromHeaderTag
233:                                            .equals(this FromHeaderTag))
234:                                    && (skipToHeader || originalToHeaderTag
235:                                            .equals(this ToHeaderTag))
236:                                    && getOriginalRequest().getCallId()
237:                                            .getCallId().equals(
238:                                                    messageToHeaderTest
239:                                                            .getCallId()
240:                                                            .getCallId())
241:                                    && getOriginalRequest().getCSeqHeader()
242:                                            .getSequenceNumber() == messageToHeaderTest
243:                                            .getCSeqHeader()
244:                                            .getSequenceNumber()
245:                                    && topViaHeader.equals(getOriginalRequest()
246:                                            .getViaHeaders().getFirst())) {
247:                                transactionMatches = true;
248:                            }
249:                        }
250:                    }
251:                }
252:
253:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
254:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
255:                            "TRANSACTION MATCHES:" + transactionMatches);
256:                }
257:
258:                return transactionMatches;
259:            }
260:
261:            /**
262:             * Sends out a trying response (only happens when the transaction is
263:             * mapped). Otherwise the transaction is not known to the stack.
264:             * @exception IOException if the attempt to send fails
265:             */
266:            protected void map() throws IOException {
267:                if (getState() == -1 || getState() == TRYING_STATE) {
268:                    if (isInviteTransaction() && !this .isMapped) {
269:                        this .isMapped = true;
270:                        // Has side-effect of setting
271:                        // state to "Proceeding"
272:                        new SendTrying(this );
273:                    } else {
274:                        isMapped = true;
275:                    }
276:                }
277:            }
278:
279:            /**
280:             * Returns true if the transaction is known to stack.
281:             * @return true if the transaction is already mapped
282:             */
283:            public boolean isTransactionMapped() {
284:                return this .isMapped;
285:            }
286:
287:            /**
288:             * Processes a new request message through this transaction.
289:             * If necessary, this message will also be passed onto the TU.
290:             *
291:             * IMPL_NOTE:
292:             * Receiving the PUBLISH request at ESC (i.e. UAS):
293:             * The event state is identified by three major pieces:
294:             * Request-URI, event-type and entity-tag (RFC3903, section 4.1).
295:             * Maybe it is needed to maintain the event state vector in our
296:             * implementation.
297:             *
298:             * @param transactionRequest Request to process.
299:             * @param sourceChannel Channel that received this message.
300:             */
301:            public void processRequest(Request transactionRequest,
302:                    MessageChannel sourceChannel) throws SIPServerException {
303:                boolean toTu = false;
304:
305:                try {
306:                    // If this is the first request for this transaction,
307:                    if (getState() == -1) {
308:                        // Save this request as the one this
309:                        // transaction is handling
310:                        setOriginalRequest(transactionRequest);
311:                        setState(TRYING_STATE);
312:                        toTu = true;
313:                        if (isInviteTransaction() && this .isMapped) {
314:                            // Has side-effect of setting
315:                            // state to "Proceeding".
316:                            sendMessage(transactionRequest.createResponse(100,
317:                                    "Trying"));
318:                        }
319:                        // If an invite transaction is ACK'ed while in
320:                        // the completed state,
321:                    } else if (isInviteTransaction()
322:                            && COMPLETED_STATE == getState()
323:                            && transactionRequest.getMethod().equals(
324:                                    Request.ACK)) {
325:                        setState(CONFIRMED_STATE);
326:                        disableRetransmissionTimer();
327:                        if (!isReliable()) {
328:                            if (this .lastResponse != null
329:                                    && this .lastResponse.getStatusCode() == Response.REQUEST_TERMINATED) {
330:                                setState(TERMINATED_STATE);
331:                            } else {
332:                                enableTimeoutTimer(TIMER_I);
333:                            }
334:                        } else {
335:                            setState(TERMINATED_STATE);
336:                        }
337:                        // Application should not Ack in CONFIRMED state
338:                        return;
339:                    } else if (transactionRequest.getMethod().equals(
340:                            getOriginalRequest().getMethod())) {
341:                        if (getState() == PROCEEDING_STATE
342:                                || getState() == COMPLETED_STATE) {
343:                            // Resend the last response to
344:                            // the client
345:                            if (lastResponse != null) {
346:                                try {
347:                                    // Send the message to the client
348:                                    getMessageChannel().sendMessage(
349:                                            lastResponse);
350:                                } catch (IOException e) {
351:                                    setState(TERMINATED_STATE);
352:                                    throw e;
353:                                }
354:                            }
355:                        } else if (transactionRequest.getMethod().equals(
356:                                Request.ACK)) {
357:                            // This is passed up to the TU to suppress
358:                            // retransmission of OK
359:                            requestOf.processRequest(transactionRequest, this );
360:                        }
361:                        return;
362:                    }
363:
364:                    // Pass message to the TU
365:                    if (COMPLETED_STATE != getState()
366:                            && TERMINATED_STATE != getState()
367:                            && requestOf != null) {
368:                        if (getOriginalRequest().getMethod().equals(
369:                                transactionRequest.getMethod())) {
370:                            // Only send original request to TU once!
371:                            if (toTu)
372:                                requestOf.processRequest(transactionRequest,
373:                                        this );
374:                        } else {
375:                            requestOf.processRequest(transactionRequest, this );
376:                        }
377:                    } else {
378:                        // need revisit
379:                        // I am allowing it through!
380:                        if (((SIPTransactionStack) getSIPStack())
381:                                .isDialogCreated(getOriginalRequest()
382:                                        .getMethod())
383:                                && getState() == TERMINATED_STATE
384:                                && transactionRequest.getMethod().equals(
385:                                        Request.ACK) && requestOf != null) {
386:                            if (!this .getDialog().ackSeen) {
387:                                (this .getDialog())
388:                                        .ackReceived(transactionRequest);
389:                                requestOf.processRequest(transactionRequest,
390:                                        this );
391:                            }
392:                        } else if (transactionRequest.getMethod().equals(
393:                                Request.CANCEL)) {
394:
395:                            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
396:                                Logging.report(Logging.INFORMATION,
397:                                        LogChannels.LC_JSR180,
398:                                        "Too late to cancel Transaction");
399:                            }
400:                        }
401:
402:                        // send OK and just ignore the CANCEL.
403:                        try {
404:                            this .sendMessage(transactionRequest
405:                                    .createResponse(Response.OK));
406:                        } catch (IOException ex) {
407:                            // Transaction is already terminated
408:                            // just ignore the IOException.
409:                        }
410:
411:                        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
412:                            Logging.report(Logging.INFORMATION,
413:                                    LogChannels.LC_JSR180, "Dropping request "
414:                                            + getState());
415:                        }
416:                    }
417:                } catch (IOException e) {
418:                    raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
419:                }
420:            }
421:
422:            /**
423:             * Sends a response message through this transactionand onto
424:             * the client.
425:             *
426:             * @param messageToSend Response to process and send.
427:             */
428:            public void sendMessage(Message messageToSend) throws IOException {
429:
430:                // Message typecast as a response
431:                Response transactionResponse;
432:                // Status code of the response being sent to the client
433:                int statusCode;
434:
435:                // Get the status code from the response
436:                transactionResponse = (Response) messageToSend;
437:                statusCode = transactionResponse.getStatusCode();
438:                Dialog dialog = this .dialog;
439:                // super.checkCancel(transactionResponse);
440:                // Provided we have set the banch id for this we set the BID for the
441:                // outgoing via.
442:                if (this .getBranch() != null) {
443:                    transactionResponse.getTopmostVia().setBranch(
444:                            this .getBranch());
445:                } else {
446:                    transactionResponse.getTopmostVia().removeParameter(
447:                            ViaHeader.BRANCH);
448:                }
449:                // Method of the response does not match the request used to
450:                // create the transaction - transaction state does not change.
451:                if (!transactionResponse.getCSeqHeader().getMethod().equals(
452:                        getOriginalRequest().getMethod())) {
453:                    sendSIPResponse(transactionResponse);
454:                    return;
455:                }
456:                if (this .dialog != null) {
457:                    if (this .dialog.getRemoteTag() == null
458:                            && transactionResponse.getTo().getTag() != null
459:                            && ((SIPTransactionStack) this .getSIPStack())
460:                                    .isDialogCreated(transactionResponse
461:                                            .getCSeqHeader().getMethod())) {
462:                        this .dialog.setRemoteTag(transactionResponse.getTo()
463:                                .getTag());
464:                        ((SIPTransactionStack) this .getSIPStack())
465:                                .putDialog(this .dialog);
466:                        if (statusCode / 100 == 1)
467:                            this .dialog.setState(Dialog.EARLY_STATE);
468:                    } else if (((SIPTransactionStack) this .getSIPStack())
469:                            .isDialogCreated(transactionResponse
470:                                    .getCSeqHeader().getMethod())) {
471:                        if (statusCode / 100 == 2) {
472:                            if (!this .isInviteTransaction()) {
473:                                this .dialog.setState(Dialog.CONFIRMED_STATE);
474:                            } else {
475:                                if (this .dialog.getState() == -1)
476:                                    this .dialog.setState(Dialog.EARLY_STATE);
477:                            }
478:                        } else if (statusCode >= 300
479:                                && statusCode <= 699
480:                                && (this .dialog.getState() == -1 || this .dialog
481:                                        .getState() == Dialog.EARLY_STATE)) {
482:                            this .dialog.setState(Dialog.TERMINATED_STATE);
483:                        }
484:                    } else if (transactionResponse.getCSeqHeader().getMethod()
485:                            .equals(Request.BYE)
486:                            && statusCode / 100 == 2) {
487:                        // Dialog will be terminated when the transction is terminated.
488:                        if (!isReliable())
489:                            this .dialog.setState(Dialog.COMPLETED_STATE);
490:                        else
491:                            this .dialog.setState(Dialog.TERMINATED_STATE);
492:                    }
493:                }
494:                // If the TU sends a provisional response while in the
495:                // trying state,
496:                if (getState() == TRYING_STATE) {
497:                    if (statusCode / 100 == 1) {
498:                        setState(PROCEEDING_STATE);
499:                    } else if (200 <= statusCode && statusCode <= 699) {
500:                        if (!isInviteTransaction()) {
501:                            setState(COMPLETED_STATE);
502:                        } else {
503:                            if (statusCode / 100 == 2) {
504:                                this .collectionTime = TIMER_J;
505:                                setState(TERMINATED_STATE);
506:                            } else
507:                                setState(COMPLETED_STATE);
508:                        }
509:                        if (!isReliable()) {
510:                            enableRetransmissionTimer();
511:                        }
512:                        enableTimeoutTimer(TIMER_J);
513:                    }
514:                    // If the transaction is in the proceeding state,
515:                } else if (getState() == PROCEEDING_STATE) {
516:                    if (isInviteTransaction()) {
517:                        // If the response is a failure message,
518:                        if (statusCode / 100 == 2) {
519:                            // Set up to catch returning ACKs
520:                            // Antonis Karydas: Suggestion
521:                            // Recall that the CANCEL's response will go
522:                            // through this transaction
523:                            // and this may well be it. Do NOT change the
524:                            // transaction state if this
525:                            // is a response for a CANCEL.
526:                            // Wait, instead for the 487 from TU.
527:                            if (!transactionResponse.getCSeqHeader()
528:                                    .getMethod().equals(Request.CANCEL)) {
529:                                setState(TERMINATED_STATE);
530:                                if (!isReliable()) {
531:                                    ((Dialog) this .getDialog())
532:                                            .setRetransmissionTicks();
533:                                    enableRetransmissionTimer();
534:
535:                                }
536:                                this .collectionTime = TIMER_J;
537:                                enableTimeoutTimer(TIMER_J);
538:                            }
539:                        } else if (300 <= statusCode && statusCode <= 699) {
540:                            // Set up to catch returning ACKs
541:                            setState(COMPLETED_STATE);
542:                            if (!isReliable()) {
543:                                enableRetransmissionTimer();
544:                            }
545:                            // Changed to TIMER_H as suggested by
546:                            // Antonis Karydas
547:                            enableTimeoutTimer(TIMER_H);
548:                            // If the response is a success message,
549:                        } else if (statusCode / 100 == 2) {
550:                            // Terminate the transaction
551:                            setState(TERMINATED_STATE);
552:                            disableRetransmissionTimer();
553:                            disableTimeoutTimer();
554:                        }
555:                        // If the transaction is not an invite transaction
556:                        // and this is a final response,
557:                    } else if (200 <= statusCode && statusCode <= 699) {
558:                        // Set up to retransmit this response,
559:                        // or terminate the transaction
560:                        setState(COMPLETED_STATE);
561:                        if (!isReliable()) {
562:                            disableRetransmissionTimer();
563:                            enableTimeoutTimer(TIMER_J);
564:                        } else {
565:                            setState(TERMINATED_STATE);
566:                        }
567:                    }
568:
569:                    if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
570:                        Logging.report(Logging.INFORMATION,
571:                                LogChannels.LC_JSR180,
572:                                "SEND MESSAGE :: SERVER TRANSACTION STATE SET "
573:                                        + getState());
574:                    }
575:
576:                    // If the transaction has already completed,
577:                } else if (getState() == COMPLETED_STATE) {
578:                    return;
579:                }
580:
581:                try {
582:                    // Send the message to the client
583:                    lastResponse = transactionResponse;
584:                    sendSIPResponse(transactionResponse);
585:                } catch (IOException e) {
586:                    setState(TERMINATED_STATE);
587:                    throw e;
588:                }
589:            }
590:
591:            /**
592:             * Gets the via host name.
593:             * @return the via host
594:             */
595:            public String getViaHost() {
596:                return encapsulatedChannel.getViaHost();
597:            }
598:
599:            /**
600:             * Gets the via port number.
601:             * @return the via port number
602:             */
603:            public int getViaPort() {
604:                return encapsulatedChannel.getViaPort();
605:            }
606:
607:            /**
608:             * Called by the transaction stack when a retransmission
609:             * timer fires. This retransmits the last response when the
610:             * retransmission filter is enabled.
611:             */
612:            protected void fireRetransmissionTimer() {
613:                try {
614:                    // Resend the last response sent by this transaction
615:                    if (isInviteTransaction()
616:                            && ((SIPTransactionStack) getSIPStack()).retransmissionFilter)
617:                        getMessageChannel().sendMessage(lastResponse);
618:                } catch (IOException e) {
619:                    raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
620:                }
621:            }
622:
623:            /**
624:             * Called by the transaction stack when a timeout timer fires.
625:             */
626:            protected void fireTimeoutTimer() {
627:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
628:                    Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
629:                            "ServerTransaction.fireTimeoutTimer "
630:                                    + this .getState() + " method = "
631:                                    + this .getOriginalRequest().getMethod());
632:                }
633:
634:                Dialog dialog = (Dialog) this .getDialog();
635:                int mystate = this .getState();
636:
637:                if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this 
638:                        .getOriginalRequest().getMethod())
639:                        && (mystate == super .CALLING_STATE || mystate == super .TRYING_STATE)) {
640:                    dialog.setState(Dialog.TERMINATED_STATE);
641:                } else if (getOriginalRequest().getMethod().equals(Request.BYE)) {
642:                    if (dialog != null)
643:                        dialog.setState(Dialog.TERMINATED_STATE);
644:                }
645:
646:                if ((getState() == CONFIRMED_STATE || getState() == COMPLETED_STATE)
647:                        && isInviteTransaction()) {
648:                    raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
649:                    setState(TERMINATED_STATE);
650:                } else if (!isInviteTransaction()
651:                        && (getState() == COMPLETED_STATE || getState() == CONFIRMED_STATE)) {
652:                    setState(TERMINATED_STATE);
653:                } else if (isInviteTransaction()
654:                        && getState() == TERMINATED_STATE) {
655:                    // This state could be reached when retransmitting
656:                    raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
657:                    if (dialog != null)
658:                        dialog.setState(Dialog.TERMINATED_STATE);
659:                }
660:            }
661:
662:            /**
663:             * Gets the last response.
664:             * @return the last response
665:             */
666:            public Response getLastResponse() {
667:                return this .lastResponse;
668:            }
669:
670:            /**
671:             * Sets the original request.
672:             * @param originalRequest original request to remember
673:             */
674:            public void setOriginalRequest(Request originalRequest) {
675:                super .setOriginalRequest(originalRequest);
676:                // ACK Server Transaction is just a dummy transaction.
677:                if (originalRequest.getMethod().equals("ACK"))
678:                    this .setState(TERMINATED_STATE);
679:
680:            }
681:
682:            /**
683:             * Sends specified Response message to a Request which is identified by the
684:             * specified server transaction identifier. The semantics for various
685:             * application behaviour on sending Responses to Requests is outlined at
686:             * {@link SipListener#processRequest(RequestEvent)}.
687:             * <p>
688:             * Note that when a UAS core sends a 2xx response to an INVITE, the server
689:             * transaction is destroyed, by the underlying JAIN SIP implementation.
690:             * This means that when the ACK sent by the corresponding UAC arrives
691:             * at the UAS, there will be no matching server transaction for the ACK,
692:             * and based on this rule, the ACK is passed to the UAS application core,
693:             * where it is processed.
694:             * This ensures that the three way handsake of an INVITE that is managed by
695:             * the UAS application and not JAIN SIP.
696:             *
697:             * @param response the Response to send to the Request
698:             * @throws IOException if an I/O error occured
699:             * @throws SipException if implementation cannot send response for any
700:             * other reason
701:             * @see Response
702:             */
703:            public void sendResponse(Response response) throws IOException,
704:                    SipException {
705:                try {
706:                    Dialog dialog = (Dialog) getDialog();
707:                    // Fix up the response if the dialog has already been established.
708:                    Response responseImpl = response;
709:                    int statusCode = responseImpl.getStatusCode();
710:                    int statusGroup = statusCode / 100;
711:                    if (statusGroup == 2
712:                            && parentStack.isDialogCreated(responseImpl
713:                                    .getCSeqHeader().getMethod())
714:                            && dialog != null && dialog.getLocalTag() == null
715:                            && responseImpl.getTo().getTag() == null) {
716:                        throw new SipException(
717:                                "ToHeader tag must be set for OK",
718:                                SipException.INVALID_MESSAGE);
719:                    }
720:
721:                    if (statusGroup == 2
722:                            && responseImpl.getCSeqHeader().getMethod().equals(
723:                                    Request.INVITE)
724:                            && responseImpl.getHeader(Header.CONTACT) == null) {
725:                        throw new SipException(
726:                                "Contact Header is mandatory for the OK",
727:                                SipException.INVALID_MESSAGE);
728:                    }
729:
730:                    // If sending the response within an established dialog, then
731:                    // set up the tags appropriately.
732:                    if (dialog != null && dialog.getLocalTag() != null) {
733:                        responseImpl.getTo().setTag(dialog.getLocalTag());
734:                    }
735:
736:                    String fromTag = getRequest().getFromHeader().getTag();
737:
738:                    // Backward compatibility slippery slope....
739:                    // Only set the from tag in the response when the
740:                    // incoming request has a from tag.
741:                    if (fromTag != null) {
742:                        responseImpl.getFromHeader().setTag(fromTag);
743:                    } else {
744:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
745:                            Logging
746:                                    .report(Logging.WARNING,
747:                                            LogChannels.LC_JSR180,
748:                                            "WARNING -- Null From tag Dialog layer in jeopardy!!");
749:                        }
750:                    }
751:
752:                    sendMessage(response);
753:
754:                    // Transaction successfully cancelled but dialog has not yet
755:                    // been established so delete the dialog.
756:                    if (Utils.equalsIgnoreCase(responseImpl.getCSeqHeader()
757:                            .getMethod(), Request.CANCEL)
758:                            && statusGroup == 2
759:                            // && (!dialog.isReInvite())
760:                            && parentStack.isDialogCreated(getOriginalRequest()
761:                                    .getMethod())
762:                            && (dialog.getState() == Dialog.INITIAL_STATE || dialog
763:                                    .getState() == Dialog.EARLY_STATE)) {
764:                        dialog.setState(Dialog.TERMINATED_STATE);
765:                    }
766:                    // See if the dialog needs to be inserted into the dialog table
767:                    // or if the state of the dialog needs to be changed.
768:                    if (dialog != null) {
769:                        dialog.printTags();
770:                        if (Utils.equalsIgnoreCase(responseImpl.getCSeqHeader()
771:                                .getMethod(), Request.BYE)) {
772:                            dialog.setState(Dialog.TERMINATED_STATE);
773:                        } else if (Utils.equalsIgnoreCase(responseImpl
774:                                .getCSeqHeader().getMethod(), Request.CANCEL)) {
775:                            if (dialog.getState() == -1
776:                                    || dialog.getState() == Dialog.EARLY_STATE) {
777:                                dialog.setState(Dialog.TERMINATED_STATE);
778:                            }
779:                        } else {
780:                            if (dialog.getLocalTag() == null
781:                                    && responseImpl.getTo().getTag() != null) {
782:                                if (statusCode != 100)
783:                                    dialog.setLocalTag(responseImpl.getTo()
784:                                            .getTag());
785:                            }
786:                            if (parentStack.isDialogCreated(responseImpl
787:                                    .getCSeqHeader().getMethod())) {
788:                                if (statusGroup == 1 && statusCode != 100) {
789:                                    dialog.setState(Dialog.EARLY_STATE);
790:                                } else if (statusGroup == 2) {
791:                                    dialog.setState(Dialog.CONFIRMED_STATE);
792:                                }
793:                                // Enter into our dialog table provided this is a
794:                                // dialog creating method.
795:                                if (statusCode != 100)
796:                                    parentStack.putDialog(dialog);
797:                            }
798:                        }
799:                    }
800:                } catch (NullPointerException npe) {
801:                    if (Logging.REPORT_LEVEL <= Logging.ERROR) {
802:                        Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
803:                                "ServerTransaction.sendResponse(): NPE occured: "
804:                                        + npe);
805:                        npe.printStackTrace();
806:                    }
807:
808:                    throw new SipException("NPE occured: " + npe.getMessage(),
809:                            SipException.GENERAL_ERROR);
810:                }
811:            }
812:
813:            /**
814:             * Returns this transaction.
815:             * @return the response message channel
816:             */
817:            public MessageChannel getResponseChannel() {
818:                return this;
819:            }
820:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.